From 8a8043573cb8150dd7c2fabadf4c2e3ff08c8d87 Mon Sep 17 00:00:00 2001 From: wangjia <809946525@qq.com> Date: Wed, 1 Jul 2026 20:46:41 +0800 Subject: [PATCH] =?UTF-8?q?refactor(client):=20=E5=BA=93=E5=AD=98=E5=B1=8F?= =?UTF-8?q?=E7=A7=BB=E9=99=A4=E9=A2=84=E8=AD=A6/=E6=B5=81=E6=B0=B4?= =?UTF-8?q?=E6=AD=BB=20tab=20=E5=8F=8A=E5=85=B3=E8=81=94=E6=AD=BB=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit build() 只渲染库存视图(预警并入 KPI 缺货卡点击筛选、流水移到商品详情), _buildWarningTab/_buildLogTab/_warningCard/_logCard/_DirectionBadge 已成死代码, 连同未用的 data_table_card/tab_state_provider/page_scaffold import 一并移除(约 -290 行)。 Co-Authored-By: Claude Opus 4.8 --- .../inventory/inventory_list_screen.dart | 339 +----------------- 1 file changed, 1 insertion(+), 338 deletions(-) diff --git a/client/lib/screens/inventory/inventory_list_screen.dart b/client/lib/screens/inventory/inventory_list_screen.dart index 4b7973c..892f2ac 100644 --- a/client/lib/screens/inventory/inventory_list_screen.dart +++ b/client/lib/screens/inventory/inventory_list_screen.dart @@ -13,8 +13,7 @@ import '../../models/inventory.dart'; import '../../core/auth/auth_state.dart'; import '../../widgets/write_guard.dart'; import '../../providers/inventory_provider.dart'; -import '../../widgets/data_table_card.dart'; -import '../../widgets/kpi_card.dart' show StatusPill; // 旧 tab/移动卡片用,待统一 DsBadge +import '../../widgets/kpi_card.dart' show StatusPill; // 移动卡片状态药丸 import 'package:lucide_icons_flutter/lucide_icons.dart'; import '../../widgets/ds/ds_atoms.dart'; import '../../widgets/ds/ds_kpi.dart'; @@ -23,14 +22,12 @@ import '../../widgets/mobile_list_card.dart'; import '../../core/theme/app_dims.g.dart'; import '../../widgets/multi_select_dropdown.dart' show ColDef, ColumnToggleButton, FilterableColumnHeader; import '../../core/storage/column_prefs.dart'; -import '../../widgets/page_scaffold.dart'; import '../../core/utils/export_util.dart'; import '../../core/utils/print_util.dart'; import '../../core/utils/dialog_util.dart'; import '../../widgets/label_preview_dialog.dart'; import '../../providers/product_provider.dart'; import '../../providers/product_option_provider.dart'; -import '../../providers/tab_state_provider.dart'; import '../../providers/shop_provider.dart' show shopInfoProvider; class InventoryListScreen extends ConsumerStatefulWidget { @@ -469,63 +466,6 @@ class _InventoryListScreenState extends ConsumerState { ); } - /// 库存预警:窄屏卡片 - Widget _warningCard(Inventory item) { - return MobileListCard( - onTap: item.productId != null - ? () => context.push('/products/${item.productId}') - : null, - title: Text(item.productName.isEmpty ? '-' : item.productName), - subtitle: item.productCode.isEmpty ? null : Text(item.productCode), - trailing: _InventoryStatusBadge(item), - fields: [ - MobileCardField('仓库', item.warehouseName.isEmpty ? '-' : item.warehouseName), - MobileCardField('当前库存', null, - valueWidget: Text( - item.quantity.toStringAsFixed(0), - style: TextStyle( - fontSize: 13, - fontWeight: FontWeight.w700, - color: item.quantity == 0 ? context.tokens.danger : context.tokens.accent), - )), - MobileCardField('安全库存', '${item.minStock}'), - MobileCardField('缺口', null, - valueWidget: Text( - '${item.minStock! - item.quantity.toInt()}', - style: TextStyle( - fontSize: 13, - color: context.tokens.danger, - fontWeight: FontWeight.w600), - )), - ], - ); - } - - /// 流水记录:窄屏卡片 - Widget _logCard(dynamic log) { - return MobileListCard( - title: Text(log.productName ?? '-'), - subtitle: Text(log.createdAt?.substring(0, 19) ?? '-'), - trailing: _DirectionBadge(log.direction), - fields: [ - MobileCardField('仓库', log.warehouseName ?? '-'), - MobileCardField('数量', null, - valueWidget: Text( - log.quantity.toStringAsFixed(0), - style: TextStyle( - fontSize: 13, - fontWeight: FontWeight.w600, - color: log.direction == 'in' - ? context.tokens.success - : context.tokens.danger), - )), - MobileCardField('变前', log.qtyBefore?.toStringAsFixed(0) ?? '-'), - MobileCardField('变后', log.qtyAfter?.toStringAsFixed(0) ?? '-'), - if (log.refType != null) MobileCardField('来源', log.refType), - ], - ); - } - @override Widget build(BuildContext context) { // 照原型 inventory.html:单视图(无 tab)。库存预警并入 KPI 缺货卡点击筛选, @@ -931,267 +871,6 @@ class _InventoryListScreenState extends ConsumerState { ); } - Widget _buildWarningTab() { - final asyncInventory = ref.watch(inventoryListProvider); - return asyncInventory.when( - loading: () => const Center(child: CircularProgressIndicator()), - error: (e, _) => Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.error_outline, size: 40, color: context.tokens.muted), - const SizedBox(height: 12), - Text('加载失败:$e', - style: TextStyle(color: context.tokens.muted), - textAlign: TextAlign.center), - const SizedBox(height: 12), - ElevatedButton( - onPressed: () => - ref.read(inventoryListProvider.notifier).reload(), - child: const Text('重试'), - ), - ], - ), - ), - data: (result) { - final warnings = result.data - .where((item) => - item.minStock != null && item.quantity < item.minStock!) - .toList(); - return DataTableCard( - totalCount: warnings.length, - page: 1, - toolbar: Row( - children: [ - Icon(Icons.warning_amber, - color: context.tokens.accent, size: 18), - const SizedBox(width: 8), - Text( - '共 ${warnings.length} 个商品库存低于安全库存', - style: TextStyle( - fontSize: 13, color: context.tokens.accent), - ), - const Spacer(), - OutlinedButton.icon( - onPressed: () => exportExcel( - filename: '库存预警', - headers: ['商品编码', '商品名称', '仓库', '当前库存', '安全库存', '缺口', '状态'], - rows: warnings.map((item) => [ - item.productCode.isEmpty ? '' : item.productCode, - item.productName.isEmpty ? '' : item.productName, - item.warehouseName.isEmpty ? '' : item.warehouseName, - item.quantity.toInt(), - item.minStock ?? 0, - item.minStock! - item.quantity.toInt(), - item.quantity == 0 ? '缺货' : '库存不足', - ]).toList(), - ), - icon: const Icon(Icons.download, size: 16), - label: const Text('导出'), - ), - ], - ), - mobileCards: warnings.map(_warningCard).toList(), - columns: const [ - DataColumn(label: Text('商品编码')), - DataColumn(label: Text('商品名称')), - DataColumn(label: Text('仓库')), - DataColumn(label: Text('当前库存'), numeric: true), - DataColumn(label: Text('安全库存'), numeric: true), - DataColumn(label: Text('缺口'), numeric: true), - DataColumn(label: Text('状态')), - ], - rows: warnings.isEmpty - ? [ - DataRow(cells: [ - const DataCell(SizedBox()), - DataCell(Text('暂无预警商品', - style: TextStyle( - color: context.tokens.muted))), - const DataCell(SizedBox()), - const DataCell(SizedBox()), - const DataCell(SizedBox()), - const DataCell(SizedBox()), - const DataCell(SizedBox()), - ]) - ] - : warnings - .map((item) => DataRow( - color: WidgetStateProperty.all( - item.quantity == 0 - ? context.tokens.danger.withOpacity(0.05) - : context.tokens.accent.withOpacity(0.04)), - cells: [ - DataCell(Text( - item.productCode.isEmpty ? '-' : item.productCode, - style: const TextStyle( - fontFamily: 'monospace', - fontSize: 12))), - DataCell(item.productId != null - ? GestureDetector( - onTap: () => context.push('/products/${item.productId}'), - child: SizedBox( - width: 180, - child: Text( - item.productName.isEmpty ? '-' : item.productName, - overflow: TextOverflow.ellipsis, - style: TextStyle( - color: context.tokens.primary, - decoration: TextDecoration.underline, - decorationColor: context.tokens.primary, - )), - ), - ) - : Text(item.productName.isEmpty ? '-' : item.productName, - overflow: TextOverflow.ellipsis)), - DataCell(Text(item.warehouseName.isEmpty ? '-' : item.warehouseName)), - DataCell(Text( - item.quantity.toStringAsFixed(0), - style: TextStyle( - fontWeight: FontWeight.w700, - color: item.quantity == 0 - ? context.tokens.danger - : context.tokens.accent), - )), - DataCell(Text('${item.minStock}')), - DataCell(Text( - '${item.minStock! - item.quantity.toInt()}', - style: TextStyle( - color: context.tokens.danger, - fontWeight: FontWeight.w600), - )), - DataCell(_InventoryStatusBadge(item)), - ], - )) - .toList(), - ); - }, - ); - } - - Widget _buildLogTab() { - final asyncLogs = ref.watch(inventoryLogProvider); - return asyncLogs.when( - loading: () => const Center(child: CircularProgressIndicator()), - error: (e, _) => Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.error_outline, size: 40, color: context.tokens.muted), - const SizedBox(height: 12), - Text('加载失败:$e', - style: TextStyle(color: context.tokens.muted), - textAlign: TextAlign.center), - const SizedBox(height: 12), - ElevatedButton( - onPressed: () => - ref.read(inventoryLogProvider.notifier).reload(), - child: const Text('重试'), - ), - ], - ), - ), - data: (result) { - final logs = result.data; - return DataTableCard( - totalCount: result.total, - page: result.page, - pageSize: result.pageSize, - onPageChanged: (p) => - ref.read(inventoryLogProvider.notifier).setPage(p), - onPageSizeChanged: (s) => - ref.read(inventoryLogProvider.notifier).setPageSize(s), - toolbar: Row( - children: [ - Icon(Icons.history, color: context.tokens.primary, size: 18), - const SizedBox(width: 8), - const Text('库存流水记录', - style: TextStyle( - fontSize: 14, fontWeight: FontWeight.w500)), - const Spacer(), - OutlinedButton.icon( - onPressed: () => exportExcel( - filename: '库存流水', - headers: ['商品名称', '仓库', '方向', '数量', '变前', '变后', '来源', '时间'], - rows: logs.map((log) => [ - log.productName ?? '', - log.warehouseName ?? '', - log.direction == 'in' ? '入库' : '出库', - log.quantity.toInt(), - log.qtyBefore?.toInt() ?? 0, - log.qtyAfter?.toInt() ?? 0, - log.refType ?? '', - log.createdAt?.substring(0, 19) ?? '', - ]).toList(), - ), - icon: const Icon(Icons.download, size: 16), - label: const Text('导出'), - ), - ], - ), - mobileCards: logs.map(_logCard).toList(), - columns: const [ - DataColumn(label: Text('商品名称')), - DataColumn(label: Text('仓库')), - DataColumn(label: Text('方向')), - DataColumn(label: Text('数量'), numeric: true), - DataColumn(label: Text('变前'), numeric: true), - DataColumn(label: Text('变后'), numeric: true), - DataColumn(label: Text('来源')), - DataColumn(label: Text('时间')), - ], - rows: logs.isEmpty - ? [ - DataRow(cells: [ - const DataCell(SizedBox()), - DataCell(Text('暂无流水记录', - style: TextStyle( - color: context.tokens.muted))), - const DataCell(SizedBox()), - const DataCell(SizedBox()), - const DataCell(SizedBox()), - const DataCell(SizedBox()), - const DataCell(SizedBox()), - const DataCell(SizedBox()), - ]) - ] - : logs - .map((log) => DataRow(cells: [ - DataCell(SizedBox( - width: 160, - child: Text(log.productName ?? '-', - overflow: TextOverflow.ellipsis), - )), - DataCell(Text(log.warehouseName ?? '-')), - DataCell(_DirectionBadge(log.direction)), - DataCell(Text( - log.quantity.toStringAsFixed(0), - style: TextStyle( - fontWeight: FontWeight.w600, - color: log.direction == 'in' - ? context.tokens.success - : context.tokens.danger), - )), - DataCell(Text( - log.qtyBefore?.toStringAsFixed(0) ?? '-')), - DataCell(Text( - log.qtyAfter?.toStringAsFixed(0) ?? '-')), - DataCell(Text(log.refType ?? '-', - style: TextStyle( - fontSize: 12, - color: context.tokens.muted))), - DataCell(Text( - log.createdAt?.substring(0, 19) ?? '-', - style: TextStyle( - fontSize: 12, - color: context.tokens.muted), - )), - ])) - .toList(), - ); - }, - ); - } } class _InventoryStatusBadge extends StatelessWidget { @@ -1212,22 +891,6 @@ class _InventoryStatusBadge extends StatelessWidget { } } -class _DirectionBadge extends StatelessWidget { - final String direction; - const _DirectionBadge(this.direction); - - @override - Widget build(BuildContext context) { - final t = context.tokens; - final isIn = direction == 'in'; - return StatusPill( - label: isIn ? '入库' : '出库', - color: isIn ? t.success : t.danger, - background: isIn ? t.okSoft : t.dangerBg, - ); - } -} - // ── 导入进度对话框 ────────────────────────────────────────── enum _ImportStage { uploading, processing, done, error }