diff --git a/.superpowers/prototype/screens/m-inventory.html b/.superpowers/prototype/screens/m-inventory.html index a5b3564..4a30f41 100644 --- a/.superpowers/prototype/screens/m-inventory.html +++ b/.superpowers/prototype/screens/m-inventory.html @@ -57,7 +57,7 @@ function render(){ if(!rows.length){ L.innerHTML=`
没有匹配的商品 · 调整筛选或搜索
`; return; } L.innerHTML=rows.map((it,i)=>`
-
${it.name}
${it.code} · ${it.spec}
+
${it.name}
${it.code} · ${it.spec} · ${it.cost}
${it.status}${it.qty} ${it.unit}
diff --git a/client/lib/screens/inventory/inventory_list_screen.dart b/client/lib/screens/inventory/inventory_list_screen.dart index 37c1b72..a6d8990 100644 --- a/client/lib/screens/inventory/inventory_list_screen.dart +++ b/client/lib/screens/inventory/inventory_list_screen.dart @@ -5,6 +5,7 @@ import 'package:lucide_icons_flutter/lucide_icons.dart'; import '../../core/responsive/responsive.dart'; import '../../core/theme/context_tokens.dart'; import '../../core/theme/app_dims.g.dart'; +import '../../core/auth/auth_state.dart'; import '../../core/storage/column_prefs.dart'; import '../../core/utils/export_util.dart'; import '../../models/inventory.dart'; @@ -114,12 +115,17 @@ class _InventoryListScreenState extends ConsumerState { ); } + // 成本仅管理员可见(与出库同口径):非管理员隐藏成本价/总价列、卡片单价、货值 KPI。 + bool get _isAdmin => ref.watch(isAdminProvider); + bool _colAllowed(ColDef c) => + _isAdmin || (c.key != 'cost' && c.key != 'price'); + // ── 列设置(原型 colBtn → openColMenu:多选保持打开) ── void _openColMenu(BuildContext anchorContext) { showDsMultiMenu( anchorContext, itemsBuilder: () => [ - for (final c in _colDefs.where((c) => !c.required)) + for (final c in _colDefs.where((c) => !c.required && _colAllowed(c))) DsMenuItem( value: c.key, label: c.label, @@ -528,6 +534,8 @@ class _InventoryListScreenState extends ConsumerState { final sub = [ if (item.productCode.isNotEmpty) item.productCode, if (item.spec.isNotEmpty) item.spec, + // 单价(成本进价)仅管理员可见(2026-07-06 用户拍板) + if (_isAdmin && item.unitPrice != null) _fmtCost(item.unitPrice!), ].join(' · '); return MCard( onTap: item.productId != null ? () => _openEditor(item) : null, @@ -626,8 +634,9 @@ class _InventoryListScreenState extends ConsumerState { .toList(); final hidden = _hiddenCols ?? {}; - final visibleCols = - _colDefs.where((c) => !hidden.contains(c.key)).toList(); + final visibleCols = _colDefs + .where((c) => !hidden.contains(c.key) && _colAllowed(c)) + .toList(); final mobile = context.isMobile; // 原型 .main{padding:22px 26px}:桌面整页留白统一在此;窄屏保持紧凑。 @@ -715,7 +724,8 @@ class _InventoryListScreenState extends ConsumerState { ), MKpiItem( label: '库存货值', - value: summary != null + // 货值=成本口径,非管理员后端抹零,前端显示占位 + value: _isAdmin && summary != null ? yuanWan(summary.stockValue) : '—', delta: _mDeltaText(valDelta, valTone), @@ -752,8 +762,9 @@ class _InventoryListScreenState extends ConsumerState { ), DsKpi( title: '库存货值', - value: - summary != null ? yuanWan(summary.stockValue) : '—', + value: _isAdmin && summary != null + ? yuanWan(summary.stockValue) + : '—', icon: LucideIcons.database, tone: DsKpiTone.ok, delta: valDelta, diff --git a/client/lib/widgets/product_editor_drawer.dart b/client/lib/widgets/product_editor_drawer.dart index 0d11fbd..57010b0 100644 --- a/client/lib/widgets/product_editor_drawer.dart +++ b/client/lib/widgets/product_editor_drawer.dart @@ -11,6 +11,7 @@ import 'package:go_router/go_router.dart'; import 'package:image_picker/image_picker.dart'; import 'package:lucide_icons_flutter/lucide_icons.dart'; +import '../core/auth/auth_state.dart'; import '../core/config/app_config.dart'; import '../core/utils/dialog_util.dart'; import '../core/responsive/responsive.dart'; @@ -356,10 +357,14 @@ class _ProductEditorDrawerState extends ConsumerState<_ProductEditorDrawer> { b('${_fmtQty(widget.qty!)} ${widget.unit ?? p.unit}'.trim()) )); } + // 成本仅管理员可见(与库存列表/出库同口径);p.purchasePrice 兜底也要一并门控 + final isAdmin = ref.watch(isAdminProvider); final cost = widget.cost ?? p.purchasePrice; - if (cost != null && cost > 0) rows.add(('成本价(单瓶)', b(_fmtMoney(cost)))); - if (widget.qty != null && cost != null && cost > 0) { - rows.add(('总成本价', b(_fmtMoney(widget.qty! * cost)))); + if (isAdmin && cost != null && cost > 0) { + rows.add(('成本价(单瓶)', b(_fmtMoney(cost)))); + if (widget.qty != null) { + rows.add(('总成本价', b(_fmtMoney(widget.qty! * cost)))); + } } if ((widget.status ?? '').isNotEmpty) { rows.add(( diff --git a/client/test/golden/goldens/inventory_list_mobile_a.png b/client/test/golden/goldens/inventory_list_mobile_a.png index 9605953..6cdb47c 100644 Binary files a/client/test/golden/goldens/inventory_list_mobile_a.png and b/client/test/golden/goldens/inventory_list_mobile_a.png differ diff --git a/client/test/golden/goldens/inventory_list_mobile_b.png b/client/test/golden/goldens/inventory_list_mobile_b.png index 8b049e1..24dd9ef 100644 Binary files a/client/test/golden/goldens/inventory_list_mobile_b.png and b/client/test/golden/goldens/inventory_list_mobile_b.png differ diff --git a/client/test/golden/goldens/inventory_list_mobile_c.png b/client/test/golden/goldens/inventory_list_mobile_c.png index 5cb9c8d..b323169 100644 Binary files a/client/test/golden/goldens/inventory_list_mobile_c.png and b/client/test/golden/goldens/inventory_list_mobile_c.png differ diff --git a/client/test/golden/goldens/m_inventory_a.png b/client/test/golden/goldens/m_inventory_a.png index 2a4a3b8..dc2de1a 100644 Binary files a/client/test/golden/goldens/m_inventory_a.png and b/client/test/golden/goldens/m_inventory_a.png differ diff --git a/client/test/golden/goldens/m_inventory_b.png b/client/test/golden/goldens/m_inventory_b.png index c20fca9..d07ea28 100644 Binary files a/client/test/golden/goldens/m_inventory_b.png and b/client/test/golden/goldens/m_inventory_b.png differ diff --git a/client/test/golden/goldens/m_inventory_c.png b/client/test/golden/goldens/m_inventory_c.png index 202b7c1..91c8d82 100644 Binary files a/client/test/golden/goldens/m_inventory_c.png and b/client/test/golden/goldens/m_inventory_c.png differ diff --git a/client/test/golden/inventory_list_golden_test.dart b/client/test/golden/inventory_list_golden_test.dart index 434e230..01c0233 100644 --- a/client/test/golden/inventory_list_golden_test.dart +++ b/client/test/golden/inventory_list_golden_test.dart @@ -242,6 +242,8 @@ List _overrides() => [ productSeriesListProvider.overrideWith(() => _FakeSeriesNotifier()), productSpecListProvider.overrideWith(() => _FakeSpecNotifier()), isReadonlyProvider.overrideWithValue(false), + // 成本列/货值/单价仅管理员可见——golden 基准取管理员形态 + isAdminProvider.overrideWithValue(true), inventorySummaryProvider.overrideWith((ref) => const InventorySummary( skuCount: 1284, stockValue: 2640000, diff --git a/client/test/golden/inventory_list_mobile_golden_test.dart b/client/test/golden/inventory_list_mobile_golden_test.dart index 425bbd8..bbd3634 100644 --- a/client/test/golden/inventory_list_mobile_golden_test.dart +++ b/client/test/golden/inventory_list_mobile_golden_test.dart @@ -165,6 +165,8 @@ List _overrides() => [ productSeriesListProvider.overrideWith(() => _FakeSeriesNotifier()), productSpecListProvider.overrideWith(() => _FakeSpecNotifier()), isReadonlyProvider.overrideWithValue(false), + // 成本列/货值/单价仅管理员可见——golden 基准取管理员形态(卡片含单价) + isAdminProvider.overrideWithValue(true), inventorySummaryProvider.overrideWith((ref) => const InventorySummary( skuCount: 1284, stockValue: 2640000,