diff --git a/lib/sub_screen/common/models/customer_display_models.dart b/lib/sub_screen/common/models/customer_display_models.dart index e23fbce..4f149e4 100644 --- a/lib/sub_screen/common/models/customer_display_models.dart +++ b/lib/sub_screen/common/models/customer_display_models.dart @@ -74,6 +74,7 @@ class CustomerDisplayProduct { required this.quantityLabel, required this.unitPrice, required this.totalPrice, + this.imageSource, this.isCombo = false, this.comboItems = const [], }); @@ -90,6 +91,9 @@ class CustomerDisplayProduct { /// 当前购物车条目的结算小计,单位为分。 final int totalPrice; + /// 商品图片来源,兼容完整网络地址和服务端返回的 OSS 相对地址;为空时展示名称首字占位。 + final String? imageSource; + /// 是否为食堂套餐;旧版副屏消息缺失该字段时为 false。 final bool isCombo; @@ -104,6 +108,7 @@ class CustomerDisplayProduct { other.quantityLabel == quantityLabel && other.unitPrice == unitPrice && other.totalPrice == totalPrice && + other.imageSource == imageSource && other.isCombo == isCombo && listEquals(other.comboItems, comboItems); } @@ -115,6 +120,7 @@ class CustomerDisplayProduct { quantityLabel, unitPrice, totalPrice, + imageSource, isCombo, Object.hashAll(comboItems), ); diff --git a/lib/sub_screen/common/utils/customer_display_coordinator.dart b/lib/sub_screen/common/utils/customer_display_coordinator.dart index 83ef619..b671965 100644 --- a/lib/sub_screen/common/utils/customer_display_coordinator.dart +++ b/lib/sub_screen/common/utils/customer_display_coordinator.dart @@ -168,13 +168,16 @@ class CustomerDisplayCoordinator extends ChangeNotifier { final unitPrice = _nonNegativeInt(data['productPrice']); final totalPrice = _nonNegativeInt(data['totalPrice']); final nature = data['nature']; + final rawImageSource = data['productPic']; if (name is! String || name.trim().isEmpty || unitPrice == null || totalPrice == null || - nature is! String) { + nature is! String || + (rawImageSource != null && rawImageSource is! String)) { return null; } + final trimmedImageSource = (rawImageSource as String?)?.trim(); String quantityLabel; if (nature == 'WEIGHT') { @@ -207,6 +210,8 @@ class CustomerDisplayCoordinator extends ChangeNotifier { quantityLabel: quantityLabel, unitPrice: unitPrice, totalPrice: totalPrice, + imageSource: + trimmedImageSource?.isEmpty == true ? null : trimmedImageSource, // 套餐组成非空时兼容主屏仅透传明细但缺失标识的过渡消息。 isCombo: rawIsCombo == true || comboItems.isNotEmpty, comboItems: List.unmodifiable(comboItems), diff --git a/lib/sub_screen/page/customer_display.dart b/lib/sub_screen/page/customer_display.dart index 4291d95..3b87fed 100644 --- a/lib/sub_screen/page/customer_display.dart +++ b/lib/sub_screen/page/customer_display.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:qr_flutter/qr_flutter.dart'; import 'package:pj_supermarket_cloud/common/style/xfj_design_tokens.dart'; +import 'package:pj_supermarket_cloud/common/values/constants.dart'; import 'package:pj_supermarket_cloud/sub_screen/common/models/customer_display_models.dart'; import 'package:pj_supermarket_cloud/sub_screen/common/utils/customer_display_coordinator.dart'; import 'package:pj_supermarket_cloud/sub_screen/page/customer_welcome.dart'; @@ -143,8 +144,8 @@ class _Header extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - height: 76 * scale, - padding: EdgeInsets.symmetric(horizontal: 22 * scale), + height: 82 * scale, + padding: EdgeInsets.symmetric(horizontal: 18 * scale), decoration: _surfaceDecoration(radius: 16 * scale), child: Row( children: [ @@ -160,33 +161,21 @@ class _Header extends StatelessWidget { 'Z', style: TextStyle( color: Colors.white, - fontSize: 24 * scale, + fontSize: _fontSize(28, scale), + height: 1, fontWeight: FontWeight.w900, ), ), ), - SizedBox(width: 14 * scale), - Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - state.businessTitle, - style: TextStyle( - color: XfjDesignTokens.ink, - fontSize: 22 * scale, - fontWeight: FontWeight.w800, - ), - ), - Text( - '顾客显示屏', - style: TextStyle( - color: XfjDesignTokens.muted, - fontSize: 14 * scale, - fontWeight: FontWeight.w500, - ), - ), - ], + SizedBox(width: 10 * scale), + Text( + state.businessTitle, + style: TextStyle( + color: XfjDesignTokens.ink, + fontSize: _fontSize(28, scale), + height: 1, + fontWeight: FontWeight.w800, + ), ), const Spacer(), if (state.maskedCustomerName != null) ...[ @@ -230,8 +219,8 @@ class _HeaderPill extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - constraints: BoxConstraints(minHeight: 44 * scale), - padding: EdgeInsets.symmetric(horizontal: 14 * scale), + constraints: BoxConstraints(minHeight: 42 * scale), + padding: EdgeInsets.symmetric(horizontal: 10 * scale), decoration: BoxDecoration( color: color.withValues(alpha: 0.08), border: Border.all(color: color.withValues(alpha: 0.22)), @@ -239,13 +228,14 @@ class _HeaderPill extends StatelessWidget { ), child: Row( children: [ - Icon(icon, color: color, size: 20 * scale), - SizedBox(width: 8 * scale), + Icon(icon, color: color, size: 22 * scale), + SizedBox(width: 5 * scale), Text( label, style: TextStyle( color: color, - fontSize: 15 * scale, + fontSize: _fontSize(18, scale), + height: 1, fontWeight: FontWeight.w700, ), ), @@ -255,12 +245,18 @@ class _HeaderPill extends StatelessWidget { } } +/// 副屏商品核对面板,集中展示商品明细、同步状态和顾客提示。 class _ProductPanel extends StatelessWidget { + /// 创建读取当前顾客屏状态的商品核对面板。 const _ProductPanel({required this.state, required this.scale}); + /// 副屏协调器产出的当前结算展示状态。 final CustomerDisplayState state; + + /// 依据副屏分辨率计算的统一缩放比例。 final double scale; + /// 构建适合远距离核对的商品区域,并在商品较多时保留纵向滚动能力。 @override Widget build(BuildContext context) { return Container( @@ -269,10 +265,10 @@ class _ProductPanel extends StatelessWidget { children: [ Padding( padding: EdgeInsets.fromLTRB( - 22 * scale, - 18 * scale, - 22 * scale, 14 * scale, + 12 * scale, + 14 * scale, + 10 * scale, ), child: Row( children: [ @@ -284,18 +280,18 @@ class _ProductPanel extends StatelessWidget { state.products.isEmpty ? '欢迎光临' : '请核对商品信息', style: TextStyle( color: XfjDesignTokens.ink, - fontSize: 24 * scale, + fontSize: _fontSize(34, scale), fontWeight: FontWeight.w800, ), ), - SizedBox(height: 4 * scale), + SizedBox(height: 2 * scale), Text( state.products.isEmpty ? '商品加入购物车后将在这里实时展示' : '本次消费共 ${state.products.length} 项商品', style: TextStyle( color: XfjDesignTokens.muted, - fontSize: 15 * scale, + fontSize: _fontSize(22, scale), ), ), ], @@ -326,8 +322,8 @@ class _ProductPanel extends StatelessWidget { Container( width: double.infinity, padding: EdgeInsets.symmetric( - horizontal: 22 * scale, - vertical: 12 * scale, + horizontal: 14 * scale, + vertical: 8 * scale, ), decoration: const BoxDecoration( color: Color(0xFFFAFAFB), @@ -337,7 +333,7 @@ class _ProductPanel extends StatelessWidget { '商品和金额由收银员实时更新,如有疑问请及时告知收银员', style: TextStyle( color: XfjDesignTokens.muted, - fontSize: 14 * scale, + fontSize: _fontSize(18, scale), ), ), ), @@ -377,7 +373,7 @@ class _EmptyProducts extends StatelessWidget { '等待添加商品', style: TextStyle( color: XfjDesignTokens.ink, - fontSize: 24 * scale, + fontSize: _fontSize(30, scale), fontWeight: FontWeight.w800, ), ), @@ -386,7 +382,7 @@ class _EmptyProducts extends StatelessWidget { '请将商品交给收银员进行结算', style: TextStyle( color: XfjDesignTokens.muted, - fontSize: 16 * scale, + fontSize: _fontSize(20, scale), ), ), ], @@ -395,16 +391,20 @@ class _EmptyProducts extends StatelessWidget { } } +/// 副屏商品列表表头,与商品行共享相同的列宽比例。 class _ProductHeader extends StatelessWidget { + /// 创建当前分辨率下的商品列表表头。 const _ProductHeader({required this.scale}); + /// 依据副屏分辨率计算的统一缩放比例。 final double scale; + /// 构建商品、数量或重量、单价和小计四列表头。 @override Widget build(BuildContext context) { return Container( - height: 48 * scale, - padding: EdgeInsets.symmetric(horizontal: 22 * scale), + height: 42 * scale, + padding: EdgeInsets.symmetric(horizontal: 10 * scale), color: const Color(0xFFFAFAFB), child: Row( children: [ @@ -418,6 +418,7 @@ class _ProductHeader extends StatelessWidget { } } +/// 副屏商品列表中的单条商品记录,可选展示套餐组成。 class _ProductRow extends StatelessWidget { /// 创建一条可同时展示主商品和套餐组成的副屏商品行。 const _ProductRow({required this.product, required this.scale}); @@ -432,11 +433,13 @@ class _ProductRow extends StatelessWidget { @override Widget build(BuildContext context) { return ConstrainedBox( - constraints: BoxConstraints(minHeight: 74 * scale), + // 单品行按当前副屏可视区容纳 10 条设置高度,字号放大后通过收紧内边距避免溢出。 + constraints: BoxConstraints(minHeight: 72 * scale), child: Padding( padding: - EdgeInsets.symmetric(horizontal: 22 * scale, vertical: 10 * scale), + EdgeInsets.symmetric(horizontal: 10 * scale, vertical: 3 * scale), child: Column( + mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Row( @@ -445,19 +448,21 @@ class _ProductRow extends StatelessWidget { flex: 5, child: Row( children: [ + _ProductImage(product: product, scale: scale), + SizedBox(width: 6 * scale), _ProductTypeBadge( isCombo: product.isCombo, scale: scale, ), - SizedBox(width: 9 * scale), + SizedBox(width: 5 * scale), Expanded( child: Text( product.name, - maxLines: 2, + maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( color: XfjDesignTokens.ink, - fontSize: 18 * scale, + fontSize: _fontSize(28, scale), fontWeight: FontWeight.w700, ), ), @@ -476,7 +481,7 @@ class _ProductRow extends StatelessWidget { ], ), if (product.isCombo && product.comboItems.isNotEmpty) ...[ - SizedBox(height: 10 * scale), + SizedBox(height: 6 * scale), _ComboContents(product: product, scale: scale), ], ], @@ -486,6 +491,66 @@ class _ProductRow extends StatelessWidget { } } +/// 商品行左侧的固定尺寸图片,网络加载与失败时均保持行高稳定。 +class _ProductImage extends StatelessWidget { + /// 创建使用当前商品图片来源的顾客屏缩略图。 + const _ProductImage({required this.product, required this.scale}); + + /// 当前商品,用于读取图片来源、占位首字和无障碍说明。 + final CustomerDisplayProduct product; + + /// 依据副屏分辨率计算的几何缩放比例。 + final double scale; + + /// 构建真实商品图片;副屏 Engine 不依赖磁盘缓存插件,使用 Flutter 原生网络图片缓存。 + @override + Widget build(BuildContext context) { + final imageSource = product.imageSource; + final imageSize = 60 * scale; + final placeholder = _buildPlaceholder(); + return Semantics( + image: true, + label: '${product.name}商品图片', + child: ClipRRect( + borderRadius: BorderRadius.circular(7 * scale), + child: SizedBox( + key: ValueKey('customer-product-image-${product.name}'), + width: imageSize, + height: imageSize, + child: imageSource == null + ? placeholder + : Image.network( + _productImageUrl(imageSource), + fit: BoxFit.cover, + loadingBuilder: (context, child, loadingProgress) => + loadingProgress == null ? child : placeholder, + errorBuilder: (context, error, stackTrace) => placeholder, + ), + ), + ), + ); + } + + /// 为无图片、加载中和加载失败场景生成一致的名称首字占位。 + Widget _buildPlaceholder() { + final trimmedName = product.name.trim(); + final shortLabel = trimmedName.isEmpty ? '商' : trimmedName.substring(0, 1); + return ColoredBox( + color: XfjDesignTokens.control, + child: Center( + child: Text( + shortLabel, + style: TextStyle( + color: XfjDesignTokens.muted, + fontSize: _fontSize(22, scale), + fontWeight: FontWeight.w800, + ), + ), + ), + ); + } +} + /// 副屏主商品类型标识,帮助顾客快速区分单品和套餐。 class _ProductTypeBadge extends StatelessWidget { /// 创建商品类型标识。 @@ -511,14 +576,14 @@ class _ProductTypeBadge extends StatelessWidget { ), child: Padding( padding: EdgeInsets.symmetric( - horizontal: 7 * scale, - vertical: 3 * scale, + horizontal: 5 * scale, + vertical: 2 * scale, ), child: Text( isCombo ? '套餐' : '单品', style: TextStyle( color: foreground, - fontSize: 13 * scale, + fontSize: _fontSize(18, scale), fontWeight: FontWeight.w700, ), ), @@ -548,10 +613,10 @@ class _ComboContents extends StatelessWidget { return Container( key: ValueKey('combo-details-${product.name}'), padding: EdgeInsets.fromLTRB( - 14 * scale, 10 * scale, - 14 * scale, - 11 * scale, + 6 * scale, + 10 * scale, + 7 * scale, ), decoration: const BoxDecoration( color: XfjDesignTokens.primarySoft, @@ -566,10 +631,10 @@ class _ComboContents extends StatelessWidget { children: [ Icon( Icons.layers_outlined, - size: 17 * scale, + size: 18 * scale, color: XfjDesignTokens.primary, ), - SizedBox(width: 7 * scale), + SizedBox(width: 5 * scale), Expanded( child: Text( '套餐内含 · 每套 ${product.comboItems.length} 样 / $totalQuantity 份', @@ -577,17 +642,17 @@ class _ComboContents extends StatelessWidget { overflow: TextOverflow.ellipsis, style: TextStyle( color: XfjDesignTokens.primary, - fontSize: 14 * scale, + fontSize: _fontSize(20, scale), fontWeight: FontWeight.w800, ), ), ), - SizedBox(width: 12 * scale), + SizedBox(width: 8 * scale), Text( '明细不单独计价', style: TextStyle( color: XfjDesignTokens.muted, - fontSize: 12 * scale, + fontSize: _fontSize(18, scale), fontWeight: FontWeight.w600, ), ), @@ -595,15 +660,15 @@ class _ComboContents extends StatelessWidget { ), for (final item in product.comboItems) Padding( - padding: EdgeInsets.only(top: 8 * scale), + padding: EdgeInsets.only(top: 5 * scale), child: Row( children: [ Icon( Icons.subdirectory_arrow_right_rounded, - size: 16 * scale, + size: 17 * scale, color: XfjDesignTokens.muted, ), - SizedBox(width: 8 * scale), + SizedBox(width: 5 * scale), Expanded( child: Text( item.name, @@ -611,17 +676,17 @@ class _ComboContents extends StatelessWidget { overflow: TextOverflow.ellipsis, style: TextStyle( color: XfjDesignTokens.ink, - fontSize: 15 * scale, + fontSize: _fontSize(21, scale), fontWeight: FontWeight.w600, ), ), ), - SizedBox(width: 12 * scale), + SizedBox(width: 8 * scale), Text( '×${item.quantity}', style: TextStyle( color: XfjDesignTokens.ink, - fontSize: 15 * scale, + fontSize: _fontSize(21, scale), fontWeight: FontWeight.w800, fontFeatures: const [FontFeature.tabularFigures()], ), @@ -635,6 +700,7 @@ class _ComboContents extends StatelessWidget { } } +/// 按商品表格的列宽比例渲染表头文本。 Widget _tableText( String value, int flex, @@ -648,13 +714,14 @@ Widget _tableText( textAlign: align, style: TextStyle( color: XfjDesignTokens.muted, - fontSize: 14 * scale, + fontSize: _fontSize(20, scale), fontWeight: FontWeight.w700, ), ), ); } +/// 按商品表格的列宽比例渲染数量或金额,并保持数字宽度稳定。 Widget _valueCell( String value, int flex, @@ -668,7 +735,7 @@ Widget _valueCell( textAlign: TextAlign.center, style: TextStyle( color: emphasized ? XfjDesignTokens.ink : XfjDesignTokens.muted, - fontSize: 17 * scale, + fontSize: _fontSize(26, scale), fontWeight: emphasized ? FontWeight.w800 : FontWeight.w600, fontFeatures: const [FontFeature.tabularFigures()], ), @@ -685,7 +752,7 @@ class _SettlementPanel extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - padding: EdgeInsets.all(20 * scale), + padding: EdgeInsets.all(16 * scale), decoration: _surfaceDecoration(radius: 16 * scale), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, @@ -694,7 +761,7 @@ class _SettlementPanel extends StatelessWidget { '实际扣款', style: TextStyle( color: XfjDesignTokens.muted, - fontSize: 15 * scale, + fontSize: _fontSize(20, scale), fontWeight: FontWeight.w700, ), ), @@ -704,7 +771,7 @@ class _SettlementPanel extends StatelessWidget { key: const ValueKey('customer-payable-price'), style: TextStyle( color: XfjDesignTokens.primary, - fontSize: 54 * scale, + fontSize: _fontSize(64, scale), height: 1.05, fontWeight: FontWeight.w900, fontFeatures: const [FontFeature.tabularFigures()], @@ -751,14 +818,15 @@ class _PriceLine extends StatelessWidget { label, style: TextStyle( color: XfjDesignTokens.muted, - fontSize: 16 * scale, + fontSize: _fontSize(22, scale), + fontWeight: FontWeight.w600, ), ), Text( _money(price), style: TextStyle( color: XfjDesignTokens.ink, - fontSize: 18 * scale, + fontSize: _fontSize(26, scale), fontWeight: FontWeight.w800, fontFeatures: const [FontFeature.tabularFigures()], ), @@ -784,6 +852,8 @@ class _PaymentStatePanel extends StatelessWidget { constraints.maxWidth * 0.54, constraints.maxHeight * 0.6, ); + // 主屏调试预览可能只有 800×600;仅在极矮区域收拢辅助说明,金额、倒计时和主提示仍保持大字号。 + final compactPaymentHint = constraints.maxHeight < 180; return Row( children: [ Container( @@ -808,30 +878,36 @@ class _PaymentStatePanel extends StatelessWidget { children: [ Text( '请扫码支付', + maxLines: 1, + overflow: TextOverflow.ellipsis, style: TextStyle( color: XfjDesignTokens.ink, - fontSize: 26 * scale, + fontSize: _fontSize(34, scale), + height: 1, fontWeight: FontWeight.w900, ), ), - SizedBox(height: 10 * scale), + SizedBox(height: 6 * scale), Text( _countdown(state.countdownSeconds), key: const ValueKey('customer-payment-countdown'), style: TextStyle( color: XfjDesignTokens.danger, - fontSize: 34 * scale, + fontSize: _fontSize(44, scale), + height: 1, fontWeight: FontWeight.w900, fontFeatures: const [FontFeature.tabularFigures()], ), ), - SizedBox(height: 8 * scale), + SizedBox(height: 5 * scale), Text( '支付完成后请勿重复扫码', + maxLines: compactPaymentHint ? 1 : 2, + overflow: TextOverflow.ellipsis, style: TextStyle( color: XfjDesignTokens.muted, - fontSize: 14 * scale, - height: 1.4, + fontSize: _fontSize(20, scale), + height: 1.2, ), ), ], @@ -855,34 +931,37 @@ class _PaymentStatePanel extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ Container( - width: 76 * scale, - height: 76 * scale, + width: 68 * scale, + height: 68 * scale, alignment: Alignment.center, decoration: BoxDecoration( color: visual.color, shape: BoxShape.circle, ), - child: Icon(visual.icon, color: Colors.white, size: 40 * scale), + child: Icon(visual.icon, color: Colors.white, size: 36 * scale), ), - SizedBox(height: 16 * scale), + SizedBox(height: 10 * scale), Text( visual.title, style: TextStyle( color: XfjDesignTokens.ink, - fontSize: 28 * scale, + fontSize: _fontSize(36, scale), + height: 1, fontWeight: FontWeight.w900, ), ), - SizedBox(height: 7 * scale), + SizedBox(height: 5 * scale), Padding( padding: EdgeInsets.symmetric(horizontal: 20 * scale), child: Text( visual.description, textAlign: TextAlign.center, + maxLines: 2, + overflow: TextOverflow.ellipsis, style: TextStyle( color: XfjDesignTokens.muted, - fontSize: 15 * scale, - height: 1.45, + fontSize: _fontSize(22, scale), + height: 1.2, ), ), ), @@ -946,7 +1025,7 @@ class _Step extends StatelessWidget { '$index', style: TextStyle( color: active ? Colors.white : XfjDesignTokens.muted, - fontSize: 14 * scale, + fontSize: _fontSize(18, scale), fontWeight: FontWeight.w800, ), ), @@ -956,7 +1035,7 @@ class _Step extends StatelessWidget { label, style: TextStyle( color: active ? XfjDesignTokens.ink : XfjDesignTokens.muted, - fontSize: 13 * scale, + fontSize: _fontSize(18, scale), fontWeight: FontWeight.w600, ), ), @@ -966,31 +1045,36 @@ class _Step extends StatelessWidget { } } +/// 商品面板顶部的结算阶段标签,用图标和文字同时表达当前状态。 class _StatusBadge extends StatelessWidget { + /// 创建与当前顾客屏场景对应的状态标签。 const _StatusBadge({required this.scenario, required this.scale}); + /// 当前结算场景,决定标签的文案、图标和语义颜色。 final CustomerDisplayScenario scenario; + + /// 依据副屏分辨率计算的统一缩放比例。 final double scale; + /// 构建紧凑但可远距离识别的商品核对状态标签。 @override Widget build(BuildContext context) { final visual = _scenarioVisual(scenario); return Container( - padding: - EdgeInsets.symmetric(horizontal: 12 * scale, vertical: 7 * scale), + padding: EdgeInsets.symmetric(horizontal: 8 * scale, vertical: 4 * scale), decoration: BoxDecoration( color: visual.color.withValues(alpha: 0.08), borderRadius: BorderRadius.circular(18 * scale), ), child: Row( children: [ - Icon(visual.icon, color: visual.color, size: 17 * scale), - SizedBox(width: 6 * scale), + Icon(visual.icon, color: visual.color, size: 20 * scale), + SizedBox(width: 4 * scale), Text( scenario.title, style: TextStyle( color: visual.color, - fontSize: 14 * scale, + fontSize: _fontSize(20, scale), fontWeight: FontWeight.w700, ), ), @@ -1066,6 +1150,20 @@ BoxDecoration _surfaceDecoration({required double radius}) { String _money(int cents) => '¥ ${(cents / 100).toStringAsFixed(2)}'; +/// 将文字缩放与布局缩放分离,小尺寸副屏仍保留远距离可读的最低字号。 +double _fontSize(double designSize, double scale) { + return designSize * math.max(scale, 0.9); +} + +/// 将主屏传来的完整地址或 OSS 相对路径转换为副屏可加载的网络地址。 +String _productImageUrl(String source) { + if (RegExp(r'^https?://', caseSensitive: false).hasMatch(source)) { + return source; + } + final separator = source.startsWith('/') || source.startsWith('?') ? '' : '/'; + return '${Constants.ossUrl}$separator$source'; +} + String _countdown(int seconds) { final minutes = seconds ~/ 60; final remainingSeconds = seconds % 60; diff --git a/test/sub_screen/customer_display_coordinator_test.dart b/test/sub_screen/customer_display_coordinator_test.dart index de089da..9817b50 100644 --- a/test/sub_screen/customer_display_coordinator_test.dart +++ b/test/sub_screen/customer_display_coordinator_test.dart @@ -11,6 +11,11 @@ void main() { expect(coordinator.state.scenario, CustomerDisplayScenario.review); expect(coordinator.state.products, hasLength(2)); expect(coordinator.state.products.last.quantityLabel, '0.36 kg'); + expect( + coordinator.state.products.first.imageSource, + '/admin/sys-file/oss/file?fileName=milk.png', + ); + expect(coordinator.state.products.last.imageSource, isNull); expect(coordinator.state.products.first.isCombo, isFalse); expect(coordinator.state.products.first.comboItems, isEmpty); expect(coordinator.state.totalPrice, 4670); @@ -272,6 +277,7 @@ Map _productEvent() { 'shopList': [ { 'productName': '纯牛奶 250ml', + 'productPic': '/admin/sys-file/oss/file?fileName=milk.png', 'productPrice': 480, 'nature': 'DEFAULT', 'productNumber': 1,