docs: update work order display plan
This commit is contained in:
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||||
|
|
||||||
**Goal:** 在装箱编号模块的信息区增加工令号(work_order_no)显示,采用"字段名称一行、实际值一行"的两行布局,排产号和工令号并排展示。
|
**Goal:** 在装箱编号模块的信息区增加工令号(work_order_no)显示。信息区不显示字段名称,只并排显示排产号和工令号的具体值,并通过更大字号和加粗突出关键信息;装箱详情页也同步显示工令号。
|
||||||
|
|
||||||
**Architecture:** 后端从 ERP 视图 `vw_productionContractData` 额外查询 `工令号` 列,通过已有的 `/box/info` 接口返回给前端。Flutter 端解析后渲染为两行布局(标签行 + 值行)。
|
**Architecture:** 后端从 ERP 视图 `vw_productionContractData` 额外查询 `工令号` 列,通过已有的 `/box/info` 接口返回给前端。Flutter 端解析后,在装箱主页面信息区和装箱详情页中展示。
|
||||||
|
|
||||||
**Tech Stack:** FastAPI + SQLAlchemy (后端), Flutter (前端), PostgreSQL (连接 ERP 视图)
|
**Tech Stack:** FastAPI + SQLAlchemy (后端), Flutter (前端), PostgreSQL (连接 ERP 视图)
|
||||||
|
|
||||||
@@ -126,8 +126,8 @@ def test_box_info_success(client: TestClient):
|
|||||||
data = resp.json()
|
data = resp.json()
|
||||||
assert data["zongpai_no"] == "26BW0011"
|
assert data["zongpai_no"] == "26BW0011"
|
||||||
assert data["paichan_no"] == "W00009"
|
assert data["paichan_no"] == "W00009"
|
||||||
assert data["work_order_no"] is not None
|
assert "work_order_no" in data
|
||||||
assert isinstance(data["work_order_no"], str)
|
assert data["work_order_no"] is None or isinstance(data["work_order_no"], str)
|
||||||
assert data["quantity"] == 80
|
assert data["quantity"] == 80
|
||||||
assert "existing_boxes" in data
|
assert "existing_boxes" in data
|
||||||
assert "max_box_no" in data
|
assert "max_box_no" in data
|
||||||
@@ -142,7 +142,7 @@ source ../../.venv/Scripts/activate # 或项目虚拟环境
|
|||||||
pytest tests/test_box_api.py -v
|
pytest tests/test_box_api.py -v
|
||||||
```
|
```
|
||||||
|
|
||||||
预期:`test_box_info_success` 通过,`work_order_no` 有值。
|
预期:`test_box_info_success` 通过,响应中包含 `work_order_no` 字段。
|
||||||
|
|
||||||
**Step 3: 格式化代码**
|
**Step 3: 格式化代码**
|
||||||
|
|
||||||
@@ -202,7 +202,7 @@ class BoxInfoResult {
|
|||||||
success: true,
|
success: true,
|
||||||
zongpaiNo: json['zongpai_no'] as String?,
|
zongpaiNo: json['zongpai_no'] as String?,
|
||||||
paichanNo: json['paichan_no'] as String?,
|
paichanNo: json['paichan_no'] as String?,
|
||||||
workOrderNo: json['work_order_no'] as String?,
|
workOrderNo: json['work_order_no']?.toString(),
|
||||||
quantity: json['quantity'] as int?,
|
quantity: json['quantity'] as int?,
|
||||||
existingBoxes: boxes,
|
existingBoxes: boxes,
|
||||||
maxBoxNo: json['max_box_no'] as int? ?? 0,
|
maxBoxNo: json['max_box_no'] as int? ?? 0,
|
||||||
@@ -270,7 +270,7 @@ setState(() {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Task 6: 重写信息区 UI — 两行布局
|
### Task 6: 重写信息区 UI — 仅显示值并突出关键信息
|
||||||
|
|
||||||
**Files:**
|
**Files:**
|
||||||
- Modify: `apps/pad_scanner/lib/pages/boxing_page.dart` (`_buildInfoArea` 方法,约第 659-744 行)
|
- Modify: `apps/pad_scanner/lib/pages/boxing_page.dart` (`_buildInfoArea` 方法,约第 659-744 行)
|
||||||
@@ -278,57 +278,41 @@ setState(() {
|
|||||||
**Step 1: 用新布局替换整个 `_buildInfoArea` 方法**
|
**Step 1: 用新布局替换整个 `_buildInfoArea` 方法**
|
||||||
|
|
||||||
将原来的 `排产号标签 → 排产号值 → 已有箱数/最大箱号` 布局,改为:
|
将原来的 `排产号标签 → 排产号值 → 已有箱数/最大箱号` 布局,改为:
|
||||||
- 第一行:`排产号:` + `工令号:`(标签行)
|
- 第一行:只显示具体值,`W00009` 和 `6-1(7)` 两列并排,不显示 `排产号:`、`工令号:` 字段名称
|
||||||
- 第二行:`W00009` + `6-1(7)`(值行)
|
- 排产号和工令号都使用更大字号、加粗,等待状态显示 `--`
|
||||||
- 第三行:`已有箱数:3箱 最大箱号:3` + `详情 →`(不变)
|
- 第二行:`已有箱数:3箱 最大箱号:3` + `详情 →`(不变)
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
Widget _buildInfoArea(bool isWaiting, ColorScheme colorScheme) {
|
Widget _buildInfoArea(bool isWaiting, ColorScheme colorScheme) {
|
||||||
final grey = isWaiting;
|
final grey = isWaiting;
|
||||||
|
final paichanText = grey ? '--' : (_paichanNo ?? '--');
|
||||||
|
final workOrderText = grey ? '--' : (_workOrderNo ?? '--');
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
// 字段名称行:排产号 + 工令号
|
// 排产号 + 工令号:只显示值,突出关键信息
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'排产号:',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 13,
|
|
||||||
color: grey ? Colors.grey : Colors.black54,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 24),
|
|
||||||
Text(
|
|
||||||
'工令号:',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 13,
|
|
||||||
color: grey ? Colors.grey : Colors.black54,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 2),
|
|
||||||
// 实际值行
|
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
_paichanNo ?? '--',
|
paichanText,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 20,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w700,
|
||||||
color: grey ? Colors.grey : Colors.black87,
|
color: grey ? Colors.grey : Colors.black87,
|
||||||
),
|
),
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
_workOrderNo ?? '--',
|
workOrderText,
|
||||||
|
textAlign: TextAlign.right,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
color: grey ? Colors.grey : Colors.black87,
|
color: grey ? Colors.grey : Colors.black87,
|
||||||
),
|
),
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
@@ -336,7 +320,7 @@ Widget _buildInfoArea(bool isWaiting, ColorScheme colorScheme) {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 10),
|
||||||
|
|
||||||
// 已有箱数 + 最大箱号 + 详情按钮(不变)
|
// 已有箱数 + 最大箱号 + 详情按钮(不变)
|
||||||
Row(
|
Row(
|
||||||
@@ -415,7 +399,102 @@ flutter analyze lib/pages/boxing_page.dart
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Task 7: 构建、安装并手动验证
|
### Task 7: 在装箱详情页显示工令号
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `apps/pad_scanner/lib/pages/boxing_page.dart` (`_openDetail` 方法)
|
||||||
|
- Modify: `apps/pad_scanner/lib/pages/boxing_detail_page.dart`
|
||||||
|
|
||||||
|
**Step 1: 给 `BoxingDetailPage` 增加工令号参数**
|
||||||
|
|
||||||
|
在 `BoxingDetailPage` 中新增 `workOrderNo` 字段,并在构造函数中要求传入:
|
||||||
|
|
||||||
|
```dart
|
||||||
|
class BoxingDetailPage extends StatelessWidget {
|
||||||
|
final String paichanNo;
|
||||||
|
final String workOrderNo;
|
||||||
|
final List<BoxDetailData> existingBoxes;
|
||||||
|
|
||||||
|
const BoxingDetailPage({
|
||||||
|
super.key,
|
||||||
|
required this.paichanNo,
|
||||||
|
required this.workOrderNo,
|
||||||
|
required this.existingBoxes,
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 2: 在详情页标题区域显示排产号和工令号**
|
||||||
|
|
||||||
|
将 AppBar 标题中的单个 `paichanNo` 文本改成更紧凑的两行展示:
|
||||||
|
|
||||||
|
```dart
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Row(
|
||||||
|
children: [
|
||||||
|
const Text('装箱详情'),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
paichanNo,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
workOrderNo,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
```
|
||||||
|
|
||||||
|
如果工令号为空,传入方应使用 `--`,避免详情页出现空白。
|
||||||
|
|
||||||
|
**Step 3: 从装箱主页面传入工令号**
|
||||||
|
|
||||||
|
修改 `_openDetail`:
|
||||||
|
|
||||||
|
```dart
|
||||||
|
void _openDetail() {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (_) => BoxingDetailPage(
|
||||||
|
paichanNo: _paichanNo ?? '',
|
||||||
|
workOrderNo: _workOrderNo ?? '--',
|
||||||
|
existingBoxes: _existingBoxes,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 4: 验证编译和静态分析**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd apps/pad_scanner
|
||||||
|
flutter analyze lib/pages/boxing_page.dart lib/pages/boxing_detail_page.dart
|
||||||
|
```
|
||||||
|
|
||||||
|
预期:无错误。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 8: 构建、安装并手动验证
|
||||||
|
|
||||||
**Step 1: 构建 APK**
|
**Step 1: 构建 APK**
|
||||||
|
|
||||||
@@ -434,16 +513,18 @@ adb install -r build/app/outputs/flutter-apk/app-release.apk
|
|||||||
|
|
||||||
在设备上操作:
|
在设备上操作:
|
||||||
1. 进入装箱编号页面
|
1. 进入装箱编号页面
|
||||||
2. 确认等待状态下信息区显示 `排产号:` 和 `工令号:` 标签并排,值均为 `--`
|
2. 确认等待状态下信息区不显示字段名称,只显示两个并排的 `--`
|
||||||
3. 扫描一个真实的执行卡(如 `26BW0011`)
|
3. 扫描一个真实的执行卡(如 `26BW0011`)
|
||||||
4. 确认信息区显示:
|
4. 确认信息区显示:
|
||||||
- 标签行:`排产号:` | `工令号:`
|
- `W00009` 和 `6-1(7)` 两个值并排
|
||||||
- 值行:`W00009`(加粗)| `6-1(7)`(常规)
|
- 两个值都比原信息区更醒目,并且加粗
|
||||||
5. 在三种模式下分别测试确认布局正确
|
- 不显示 `排产号:`、`工令号:` 标签
|
||||||
|
5. 点击 `详情 →`,确认装箱详情页显示排产号和工令号
|
||||||
|
6. 在三种模式下分别测试确认布局正确
|
||||||
|
|
||||||
**Step 4: 提交**
|
**Step 4: 提交**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git add apps/pad_scanner/lib/services/api_service.dart apps/pad_scanner/lib/pages/boxing_page.dart
|
git add apps/pad_scanner/lib/services/api_service.dart apps/pad_scanner/lib/pages/boxing_page.dart apps/pad_scanner/lib/pages/boxing_detail_page.dart
|
||||||
git commit -m "feat(boxing): display work order number in info area with two-row layout"
|
git commit -m "feat(boxing): display work order number in boxing views"
|
||||||
```
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user