66e54af8c6
后端: - feat(backend): 重命名 Batches→Products 接口,新增库存状态(在售/已卖出)和买家信息 - feat(backend): 出库单创建/提交时校验仓库库存,不足则返回明确错误信息 - fix(backend): 出库创建 status 判断逻辑修复(空值默认 draft) 前端: - feat(client): 批次追踪改为商品追踪,新增状态列(在售/已卖出)和买家/时间列 - fix(client): 无批次号时显示"无批次"而非空 - refactor(client): BatchRecord → ProductTrackingRecord,repository 接口更新 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
69 lines
2.5 KiB
Markdown
69 lines
2.5 KiB
Markdown
# Flutter 布局 Bug 报告
|
||
|
||
## BUG-001
|
||
|
||
**严重程度**:高
|
||
|
||
**问题描述**:
|
||
`DataTableCard` 将 toolbar 包裹在 `SingleChildScrollView(scrollDirection: Axis.horizontal)` 中,
|
||
而 toolbar 内使用了 `Spacer`(`Flexible` 组件)。`Spacer` 在无界宽度约束下无法布局,导致运行时
|
||
抛出 Flutter assertion:
|
||
|
||
```
|
||
RenderFlex children have non-zero flex but incoming width constraints are unbounded.
|
||
```
|
||
|
||
受影响页面:
|
||
- `ProductsScreen`(`products_screen.dart:139`)
|
||
- `PartnersScreen`(`partners_screen.dart`)
|
||
- `StockInListScreen`(`stock_in_list_screen.dart`)
|
||
|
||
**复现步骤**:
|
||
1. 打开包含 `DataTableCard` 的任意页面(商品、往来单位、入库单等)
|
||
2. 由于 `SingleChildScrollView` 提供无界宽度,toolbar 中的 `Spacer` 无法展开
|
||
3. Flutter 抛出断言错误,页面渲染失败(测试中表现为所有 Widget 测试失败)
|
||
|
||
**失败的测试用例**:
|
||
所有 `products_screen_test.dart`、`partners_screen_test.dart`、`stock_in_screen_test.dart` 中的
|
||
测试均失败,错误来自 `data_table_card.dart:35` 的布局计算。
|
||
|
||
**根因分析**:
|
||
`client/lib/widgets/data_table_card.dart` 第 33-46 行:
|
||
```dart
|
||
SingleChildScrollView(
|
||
scrollDirection: Axis.horizontal,
|
||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||
child: Row(
|
||
children: [
|
||
ConstrainedBox(
|
||
constraints: BoxConstraints(
|
||
minWidth: (MediaQuery.of(context).size.width - 212 - 24).clamp(0.0, double.infinity),
|
||
),
|
||
child: toolbar!, // toolbar 中含有 Spacer,而父容器宽度无界
|
||
),
|
||
],
|
||
),
|
||
),
|
||
```
|
||
|
||
`ConstrainedBox` 设置了 `minWidth`,但 `SingleChildScrollView` 为子组件提供的是
|
||
`BoxConstraints(minWidth, Infinity)` — 最大宽度无界。`Spacer` 尝试填充剩余空间
|
||
(即无限空间),触发 Flutter 的约束断言。
|
||
|
||
**修复建议**:
|
||
方案 A:将 `ConstrainedBox` 改为固定宽度的 `SizedBox`,让 toolbar 占满 `minWidth`,
|
||
并把 toolbar 的 `Spacer` 替换为 `MainAxisAlignment.spaceBetween` 或
|
||
`SizedBox(width: X)` 固定间距:
|
||
|
||
```dart
|
||
// data_table_card.dart - 去掉 SingleChildScrollView 横向滚动,
|
||
// 改用固定宽度容器,或让 toolbar Row 使用 mainAxisSize: MainAxisSize.min
|
||
SizedBox(
|
||
width: (MediaQuery.of(context).size.width - 212 - 24).clamp(0.0, double.infinity),
|
||
child: toolbar!,
|
||
)
|
||
```
|
||
|
||
方案 B:在各 Screen 的 toolbar Row 中将 `Spacer()` 替换为 `SizedBox(width: 8)`,
|
||
并在 `DataTableCard` 中改用非横向滚动的固定宽度容器。
|