Compare commits

...

4 Commits

Author SHA1 Message Date
Misaka_Company
a7570891c5 refine multi-code detail entry 2026-05-18 15:06:56 +08:00
Misaka_Company
df3569ba22 docs update single-code boxing UI 2026-05-18 14:59:53 +08:00
Misaka_Company
1dc9e3d3a1 refactor single-code boxing UI 2026-05-18 14:54:07 +08:00
Misaka_Company
f964c76382 feat: refactor multi-code boxing UI with compact v2 layout
Merge box number and paichan info into a single header bar,
compress list rows to 40px with left color bars, fix bottom
operation area (scan/submit/finish) above status bar, and
shrink notification bars and status bar for more list space.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-18 13:58:50 +08:00
8 changed files with 7615 additions and 834 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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重构后布局
```
AppBar44px ← 固定顶部
[通知条 × 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不变

View File

@@ -0,0 +1,191 @@
# PRD · 多码凑箱页面布局优化
**模块**:装箱编号 > 多码凑箱模式BoxingMode.multiCode
**文件**`lib/pages/boxing_page.dart`(主要影响 `_buildManyToOneBody` 及相关子方法)
**版本**v2
**状态**:待评审
---
## 1. 背景与目标
多码凑箱页面在手持 PDA / 手机屏幕(宽度约 375390px上使用时原版布局存在以下问题
- **垂直空间浪费**AppBar、箱号区、排产信息区各自独占一行三块合计高度约 140px挤压了中间列表区的可视行数。
- **操作区随列表滚动**:扫码区和提交区位于列表下方,装入项目多时需要下拉才能看到操作控件,增加操作摩擦。
- **信息层次不清晰**:删除确认使用弹窗,打断了列表的整体感知;通知条与内容区边界不明确。
**优化目标**:在同一屏内展示更多已装入项目,同时保持操作控件始终可见,整体界面整洁、层次分明。
---
## 2. 改动总览
| 区域 | 原版高度(估算) | v2 高度(估算) | 节省 |
|------|--------------|--------------|------|
| AppBar | ~52px | 44px | 8px |
| 箱号区 + 排产信息区 | ~80px两行 | 48px合并一行 | 32px |
| 列表每行 | ~4852px | 40px | 812px/行 |
| 通知条(每条) | ~36px | 30px | 6px |
| 状态栏 | ~38px | 28px | 10px |
三项以上改动叠加后,典型场景下可多显示 **12 条**已装入记录,且操作底栏固定可见。
---
## 3. 详细改动说明
### 3.1 AppBar`_buildAppBar`
**原版**:高度约 52px标题与模式切换按钮分布松散模式徽章内边距较大。
**v2**
- 高度收紧至 **44px**Material 标准最小可触高度)。
- 标题(`装箱编号`)与模式徽章(`⇄ 多码凑箱 P2`)左右对齐,中间用弹性空白(`Spacer`)分隔。
- 模式徽章内边距从 `6px 10px` 收窄至 `3px 9px`,字号保持 `11px`,快捷键角标用半透明背景小标签呈现。
---
### 3.2 箱号区 + 排产信息区 → 合并为 `header-bar``_buildManyToOneBoxNoPanel`
**原版**箱号输入框22px 标签 + 44px 输入框)与排产信息行(排产号、已有箱数、最大箱号、详情按钮)分两个独立区块,共约 80px。
**v2**:合并为单行 `header-bar`,高度约 **48px**,布局如下:
```
[ 箱号 ██ 1 ██ ] │ W00009 已有 1 箱 · 最大箱号 1 详情
```
- 箱号输入框:宽 52px高 32px字号 18px 加粗,左侧配 `11px` 灰色小标签"箱号"。
- 竖向分隔线将箱号区与排产信息区视觉隔开。
- 排产号(`13px` 加粗)+ 统计信息(`11px` 灰色)两行叠放,`flex: 1` 撑满中间。
- `详情` 链接按钮右对齐,无数据时置灰。
**影响代码**`_buildManyToOneBoxNoPanel()`、相关 `_boxNoController` 绑定逻辑不变,仅 UI 结构调整。
---
### 3.3 已装入列表(`_buildManyToOnePackedList`
**原版**:每行 `packed-item` 高度约 4852px内含 `8px 8px` 内边距,信息横排一行。
**v2**:每行高度压缩至 **40px**,采用左侧色条 + 两行叠放的结构:
```
序号 ▌ 26BW0011 80 / 80 ✏️ 🗑
▌ WO-2026-001
```
- **左侧色条**(宽 3px高 26px圆角正常 = 绿色,编辑中 = 琥珀色,删除确认 = 红色。用色条替代原版整行背景色染色,减少视觉干扰。
- **序号列**(宽 14px灰色小字方便操作者快速定位。
- **主信息列**:总排号 `12px` 加粗(上行)+ 工单号 `11px` 灰色(下行),`overflow: ellipsis` 防止溢出。
- **数量列**`12px` 加粗绿色,格式 `已装 / 总量`
- **操作按钮**:✏️(编辑)/ 🗑(删除),触摸区域 28×28px悬停背景 `#eeeeee`
**编辑态**:数量文字替换为 52px 宽输入框,操作按钮变为 ✓(保存)/ ✕(取消)。
**删除确认态**:废弃弹窗方案,改为**行内展开次级条**(高度约 26px与触发行紧邻包含`删除` / `取消` 两个小按钮。行背景变淡红,色条变红,视觉上整体标记该条目处于危险操作中。
**列表头**sticky高度约 30px`已装入本箱` 左对齐,`N 项` 蓝色右对齐,固定在列表顶部,滚动时不消失。
---
### 3.4 底部操作区固定化(`_buildManyToOneScanArea` + `_buildManyToOneSubmitArea`
**原版**:扫码区、数量输入、确认按钮、完成本箱按钮位于列表下方,随列表内容延伸,装入项目多时操作区不可见。
**v2**:底部操作区改为**固定底栏(不参与滚动)**,从上至下分三行:
```
┌──────────────────────────────────────────┐
│ [✓ 26BW0014 · WO-004 · 50件] │ 扫码条 ~38px
│ 数量 [ 50 ] [确认] │ 提交行 ~48px
│ [ 完成本箱 ] │ 完成行 ~50px
└──────────────────────────────────────────┘
```
**扫码条**
- 等待状态:灰色背景,`📷 请扫描执行卡二维码`,文字灰色。
- 已扫码状态:浅绿背景,`✓ 总排号 · 工单号 · N件`,文字绿色,绿色边框。
**提交行**
- `数量` 标签(`11px`+ 输入框(`flex:1`,高 34px+ 确认按钮(高 34px`padding 0 18px`)。
- 未扫码时:输入框禁用,确认按钮灰色不可点。
- 已扫码时:输入框激活,确认按钮蓝色可点。
**完成本箱行**
- 全宽描边按钮(高 36px圆角 8px有已装入项时激活否则灰色。
---
### 3.5 通知条Alert Bars
**原版**:每条高度约 36px字号 13px内边距 `8px 16px`
**v2**
- 高度压缩至约 **30px**,内边距 `6px 12px`,字号 `12px`
- 多条通知可叠加显示(同步条 + 警告条并存场景6
- 各通知类型颜色语义不变:橙(同步中)/ 琥珀(警告)/ 蓝(信息)/ 黄(重复箱号)。
- 同步条保留旋转动画小图标(`12px``0.7s` 线性)。
---
### 3.6 状态栏(`StatusBar`
**原版**:高度约 38px背景 `#f0f0f0`,内边距 `12px 16px`
**v2**
- 高度压缩至约 **28px**,内边距 `6px 12px`
- 状态点直径从 8px 缩至 7px文字从 14px 缩至 12px。
- 颜色语义不变(蓝/绿/橙/红/琥珀)。
---
## 4. 整体布局结构v2
```
┌──────────────────────────────────────────┐ 44px
│ 装箱编号 [⇄ 多码凑箱 P2] │ AppBar
├──────────────────────────────────────────┤
│ [通知条,可叠加,每条 ~30px] │ 可选
├──────────────────────────────────────────┤ 48px
│ 箱号 [ 1 ] │ W00009 已有1箱·最大箱1 详情│ header-bar
├──────────────────────────────────────────┤
│ 已装入本箱sticky 3 项 │ ~30px
│ 1 ▌ 26BW0011 WO-001 80/80 ✏️ 🗑 │ 40px
│ 2 ▌ 26BW0012 WO-002 60/60 ✏️ 🗑 │ 40px
│ 3 ▌ 26BW0013 WO-003 40/40 ✏️ 🗑 │ 40px ← 可滚动
│ ... │
├──────────────────────────────────────────┤
│ [✓ 26BW0014 · WO-004 · 50件] │ ~38px 固定
│ 数量 [ 50 ] [确认] │ ~48px 固定
│ [ 完成本箱 ] │ ~50px 固定
├──────────────────────────────────────────┤ 28px
│ ● 装箱成功,请继续扫码 │ 状态栏
└──────────────────────────────────────────┘
```
---
## 5. 影响范围
| 方法/组件 | 改动类型 |
|-----------|---------|
| `_buildManyToOneBody()` | 结构重组(列表区 + 固定底栏) |
| `_buildManyToOneBoxNoPanel()` | 重写(合并为 header-bar |
| `_buildManyToOnePackedList()` | 重写(行高、色条、内联删除确认) |
| `_buildManyToOneScanArea()` | 移入固定底栏,样式调整 |
| `_buildManyToOneSubmitArea()` | 移入固定底栏,高度调整 |
| `_buildAppBar()` 多码分支 | 高度和内边距调整 |
| `StatusBar` widget | 尺寸参数调整 |
| Alert bar 区域 | 内边距和字号调整 |
业务逻辑(`decideMultiCodePaichanContext``_applyAutoFill``_onSubmitSuccess``_finishManyToOneBox` 等)**不受影响**。
---
## 6. 不在本次范围内
- 单码装箱模式(`BoxingMode.single`)的布局不做调整。
- 字体、主题色、品牌色系不做变更。
- 横屏/平板适配留作后续专项。

File diff suppressed because it is too large Load Diff

View File

@@ -33,23 +33,24 @@ class StatusBar extends StatelessWidget {
final colorScheme = Theme.of(context).colorScheme; final colorScheme = Theme.of(context).colorScheme;
return Container( return Container(
width: double.infinity, width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), height: 28,
padding: const EdgeInsets.symmetric(horizontal: 12),
color: colorScheme.surfaceContainerHighest, color: colorScheme.surfaceContainerHighest,
child: Row( child: Row(
children: [ children: [
Container( Container(
width: 8, width: 6,
height: 8, height: 6,
decoration: BoxDecoration( decoration: BoxDecoration(
color: _resolveDotColor(context), color: _resolveDotColor(context),
shape: BoxShape.circle, shape: BoxShape.circle,
), ),
), ),
const SizedBox(width: 8), const SizedBox(width: 7),
Expanded( Expanded(
child: Text( child: Text(
text, text,
style: const TextStyle(fontSize: 14), style: const TextStyle(fontSize: 11),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
), ),