feat:医院支付,选择支付钱包支付

This commit is contained in:
dzc committed 2025-08-14 20:05:56 +08:00
1 parent c2707899db
commit 3a7ca1e5be
17 files changed
+441 -117

No files matched your search

+12
View File
@@ -63,4 +63,16 @@ abstract class WalletApi {
?.map<ServiceMchRule>((e) => ServiceMchRule.fromJson(e))
.toList();
}
/// 获取钱包规则(android离线计算展示使用)
static Future<List<ServiceWallet>?> getWalletList(dynamic pa) async {
final res = await HttpManage().dio.get(
"/wallet/wallet-manage/ad/wallet/list",
queryParameters: pa,
);
if (res.data == null) return null;
return res.data
?.map<ServiceWallet>((e) => ServiceWallet.fromJson(e))
.toList();
}
}
@@ -94,3 +94,43 @@ class ServiceMchRule {
Map<String, dynamic> toJson() => _$ServiceMchRuleToJson(this);
}
@JsonSerializable()
class ServiceWallet {
/// 钱包id
String id;
/// 唯一编号
String walletTypeUniqueCode;
/// 用户id
String userId;
/// 钱包类型
String walletTypeId;
/// 余额(单位分)
int balance = 0;
/// 卡号
String? cardNumber;
/// 是否冻结饭卡
@JsonKey(fromJson: JsonTool.stringToBoolean, toJson: JsonTool.booleanToString)
bool? walletIsFreeze;
ServiceWallet({
required this.id,
required this.walletTypeUniqueCode,
required this.userId,
required this.walletTypeId,
required this.balance,
this.cardNumber,
this.walletIsFreeze,
});
factory ServiceWallet.fromJson(Map<String, dynamic> json) =>
_$ServiceWalletFromJson(json);
Map<String, dynamic> toJson() => _$ServiceWalletToJson(this);
}
@@ -58,3 +58,24 @@ Map<String, dynamic> _$ServiceMchRuleToJson(ServiceMchRule instance) =>
'basePrice': JsonTool.intToString(instance.basePrice),
'multiple': JsonTool.intToString(instance.multiple),
};
ServiceWallet _$ServiceWalletFromJson(Map<String, dynamic> json) =>
ServiceWallet(
id: json['id'] as String,
walletTypeUniqueCode: json['walletTypeUniqueCode'] as String,
userId: json['userId'] as String,
walletTypeId: json['walletTypeId'] as String,
balance: (json['balance'] as num).toInt(),
walletIsFreeze:
JsonTool.stringToBoolean(json['walletIsFreeze'] as String),
);
Map<String, dynamic> _$ServiceWalletToJson(ServiceWallet instance) =>
<String, dynamic>{
'id': instance.id,
'walletTypeUniqueCode': instance.walletTypeUniqueCode,
'userId': instance.userId,
'walletTypeId': instance.walletTypeId,
'balance': instance.balance,
'walletIsFreeze': JsonTool.booleanToString(instance.walletIsFreeze),
};
@@ -132,7 +132,6 @@ const _$OrderPayDisplayTypeEnumMap = {
OrderPayDisplayType.cash: 'cash',
OrderPayDisplayType.zyy: 'zyy',
OrderPayDisplayType.rmyy: 'rmyy',
OrderPayDisplayType.qrCodeScan: 'qrCodeScan',
};
UserSetting _$UserSettingFromJson(Map<String, dynamic> json) => UserSetting(
+1
View File
@@ -6,6 +6,7 @@ enum MqtActionEnum implements BaseEnum {
CANTEEN_CLASSIFY("30", "食堂分类变化"),
SUPERMARKET_PRODUCT("40", "超市商品变化"),
SUPERMARKET_CLASSIFY("50", "超市分类变化"),
SUPERMARKET("51", "超市分类变化"),
PRINT("60", "打印变化"),
FACE("70", "人脸变化"),
TAKE_FOOD_BROADCAST("80", "定餐广播"),
+1
View File
@@ -20,6 +20,7 @@ const _$MqtActionEnumEnumMap = {
MqtActionEnum.CANTEEN_CLASSIFY: 'CANTEEN_CLASSIFY',
MqtActionEnum.SUPERMARKET_PRODUCT: 'SUPERMARKET_PRODUCT',
MqtActionEnum.SUPERMARKET_CLASSIFY: 'SUPERMARKET_CLASSIFY',
MqtActionEnum.SUPERMARKET: 'SUPERMARKET',
MqtActionEnum.PRINT: 'PRINT',
MqtActionEnum.FACE: 'FACE',
MqtActionEnum.TAKE_FOOD_BROADCAST: 'TAKE_FOOD_BROADCAST',
@@ -1,13 +1,12 @@
import 'package:pj_supermarket_cloud/common/index.dart';
enum OrderPayDisplayType implements BaseEnum {
qrCode("1", "二维码支付", false),
walletCard("2", "饭卡支付", true),
face("3", "人脸支付", true),
cash("4", "现金支付", true),
zyy("12", "中医院", true),
rmyy("13", "人民医院", true),
qrCodeScan("22", "钱包扫一扫", false),
qrCode("1", "二维码支付", false, 1),
walletCard("2", "饭卡支付", true, 2),
face("3", "人脸支付", true, 3),
cash("4", "现金支付", true, 4),
zyy("12", "中医院", true, 5),
rmyy("13", "人民医院", true, 6),
;
@override
@@ -16,6 +15,35 @@ enum OrderPayDisplayType implements BaseEnum {
final String title;
// 是否支离线支付
final bool supportOffLine;
// 是否支离线支付
final int order;
const OrderPayDisplayType(this.code, this.title, this.supportOffLine);
// 线下支付的订单类型(现金支付,其他渠道支付如中医院、人民医院)
static const List<OrderPayDisplayType> offlinePayTypeList = [
OrderPayDisplayType.cash,
OrderPayDisplayType.zyy,
OrderPayDisplayType.rmyy,
];
// 是否为线下支付
static bool isOffline(OrderPayDisplayType type) {
return offlinePayTypeList.contains(type);
}
// 需要选择钱包
static const List<OrderPayDisplayType> selectWalletPayTypeList = [
OrderPayDisplayType.face,
];
// 是否需要选择钱包
static bool isSelectWalletPayType(OrderPayDisplayType type) {
return selectWalletPayTypeList.contains(type);
}
const OrderPayDisplayType(
this.code,
this.title,
this.supportOffLine,
this.order,
);
}
+4
View File
@@ -89,6 +89,10 @@ class AppMqTool {
await SyncProductTool.syncProduct();
mqUpdateEventBus.fire(MqtActionEnum.SUPERMARKET_PRODUCT);
break;
case MqtActionEnum.SUPERMARKET:
await SyncProductTool.syncSupermarket();
mqUpdateEventBus.fire(MqtActionEnum.SUPERMARKET);
break;
case MqtActionEnum.CANTEEN_CLASSIFY:
await SyncProductTool.syncClassify();
mqUpdateEventBus.fire(MqtActionEnum.CANTEEN_CLASSIFY);
+11 -8
View File
@@ -25,16 +25,19 @@ abstract class AppUserTool {
}
// 生成外部用户
static ServiceUser generateExternalUser({
String userId = "-1",
String userName = "外部用户",
String cardNumber = "-1",
}) {
static ServiceUser generateExternalUser() {
return ServiceUser(
userId: userId,
username: userName,
walletCardNumber: cardNumber,
userId: "-1",
username: "外部用户",
userMobile: "外部用户",
walletIsFreeze: null,
);
}
// 是否为外部用户
static bool isGenerateExternalUser(ServiceUser user) {
return user.userId == "-1" &&
user.userMobile == "外部用户" &&
user.username == "外部用户";
}
}
@@ -1,4 +1,5 @@
import 'package:common_utils/common_utils.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:get/get.dart';
import 'package:pinyin/pinyin.dart';
@@ -167,6 +168,33 @@ abstract class SyncProductTool {
// 同步商品分类 spu end
// **************************************************************************
/// 同步超市所有数据
/// 1-删除所有商品分类
/// 2-删除所有商品
/// 3-同步商品分类
/// 4-同步商品
static Future<void> syncSupermarket() async {
final stopwatch = Stopwatch()..start();
EasyLoading.show(
status: '原创同步数据中...',
maskType: EasyLoadingMaskType.black,
);
try {
// 删除
await delDatabase();
// 同步
await syncClassify();
await syncProduct();
} catch (error, stack) {
logger.e(
"|$_tag|同步|${SysType.SUPERMARKET.title}|商品信息意外的错误error:|$error|,stack:|$stack|");
} finally {
stopwatch.stop();
logger.i('|$_tag|同步超市数据总耗时: ${stopwatch.elapsedMilliseconds}ms');
EasyLoading.dismiss();
}
}
/// 同步商品
static Future<void> syncProduct() async {
final sysSetting = await AppSettingTool.getSysSetting();
+1 -1
View File
@@ -12,7 +12,7 @@ class Constants {
/// 服务 url
static const apiUrl = 'https://stgl.pj.gov.cn/api';
// static const apiUrl = 'http://192.168.101.139:9999';
// static const apiUrl = 'http://192.168.101.174:9999';
/// 静态资源 url
static const ossUrl = apiUrl;
@@ -0,0 +1,97 @@
import 'package:common_utils/common_utils.dart';
import 'package:ducafe_ui_core/ducafe_ui_core.dart';
import 'package:flutter/material.dart';
import 'package:forui/forui.dart';
import 'package:get/get.dart';
import 'package:pj_supermarket_cloud/common/index.dart';
final _successColor = Colors.greenAccent[200];
Widget AppWalletSelector(
BuildContext context, {
required List<ServiceWallet> list,
required Function(ServiceWallet) onChange,
ServiceWallet? selector,
}) {
if (ObjectUtil.isEmpty(list)) {
return const SizedBox();
}
final currentSelector = selector ?? list[0];
final theme = FTheme.of(context);
return list
.map((v) {
// 钱包类型映射
final walletTypeStr = WalletType.values
.firstWhereOrNull(
(item) => item.code == v.walletTypeUniqueCode,
)
?.title ??
"未知钱包";
// 是否选中
final isSelect =
v.walletTypeUniqueCode == currentSelector.walletTypeUniqueCode;
return <Widget>[
FIcon(
FAssets.icons.walletMinimal,
size: theme.typography.xl.fontSize,
),
SizedBox(width: 10.w),
Text(
walletTypeStr,
style: theme.typography.xl.copyWith(height: 1),
),
SizedBox(width: 10.w),
appPrice(context, v.balance),
const Spacer(),
FIcon(
FAssets.icons.circleCheck,
color: Colors.green,
size: theme.typography.xl2.fontSize,
).offstage(
offstage: !isSelect,
),
]
.toRow()
.padding(
vertical: 15.h,
horizontal: 20.w,
)
.decorated(
color: !isSelect ? theme.colorScheme.background : _successColor,
border: Border.all(
color: theme.colorScheme.primary,
width: 1,
),
borderRadius: theme.style.borderRadius / 2,
)
.onTap(() => onChange(v));
})
.toList()
.toColumnSpace(space: 10.w)
.padding(
vertical: 10.h,
horizontal: 10.w,
);
}
// list.add(
// ServiceWallet(
// id: "1",
// walletTypeUniqueCode: "1",
// userId: "1",
// walletTypeId: "1",
// balance: 100,
// ),
// );
// list.add(
// ServiceWallet(
// id: "2",
// walletTypeUniqueCode: "2",
// userId: "2",
// walletTypeId: "2",
// balance: 200,
// ),
// );
+1
View File
@@ -16,6 +16,7 @@ export './app/app_page.dart';
export './app/app_price.dart';
export './app/app_radio_hour_type_dialog.dart';
export './app/app_title.dart';
export './app/app_wallet_selector.dart';
export './card/card_common.dart';
@@ -59,6 +59,12 @@ class SelectPayTypeDialogController extends GetxController {
StreamSubscription<FaceStream?>? faceDiscernListen;
// 钱包类标
RxList<ServiceWallet> userWalletList = RxList<ServiceWallet>([]);
// 当前选择的钱包
Rx<ServiceWallet?> currentWallet = Rx<ServiceWallet?>(null);
// 二维码识别结果
ServiceQRCode? globalQrCode;
@@ -78,6 +84,22 @@ class SelectPayTypeDialogController extends GetxController {
if (payType == null || payType == orderPayDisplayType.value) {
return;
}
final isOffline = OrderPayDisplayType.isOffline(payType);
if (isOffline) {
payUser.value = AppUserTool.generateExternalUser();
if (payType == OrderPayDisplayType.cash) {
orderPayType.value = OrderPayType.CASH;
} else if (payType == OrderPayDisplayType.zyy) {
orderPayType.value = OrderPayType.ZYY;
} else if (payType == OrderPayDisplayType.rmyy) {
orderPayType.value = OrderPayType.RMYY;
}
} else if (payUser.value != null) {
if (AppUserTool.isGenerateExternalUser(payUser.value!)) {
payUser.value = null;
}
}
orderPayDisplayType.value = payType;
orderPayDisplayType.refresh();
});
@@ -98,12 +120,14 @@ class SelectPayTypeDialogController extends GetxController {
final isNetwork = AppNetworkTool.isAutoNetwork();
// 过滤一下不支持离线的支付方式
if (isNetwork) {
usePayDisplayTypeList.value = appSetting.usePayDisplayType!;
usePayDisplayTypeList.value = appSetting.usePayDisplayType!.toList()
..sort((a, b) => a.order.compareTo(b.order));
} else {
final supportPayTypeList = appSetting.usePayDisplayType!
.where((i) => i.supportOffLine)
.toList();
usePayDisplayTypeList.value = supportPayTypeList;
usePayDisplayTypeList.value = supportPayTypeList.toList()
..sort((a, b) => a.order.compareTo(b.order));
}
}
}
@@ -138,9 +162,6 @@ class SelectPayTypeDialogController extends GetxController {
case OrderPayDisplayType.face:
await _dispatchFace();
break;
case OrderPayDisplayType.cash:
await _dispatchCash();
break;
default:
}
onRecognition?.call();
@@ -151,6 +172,12 @@ class SelectPayTypeDialogController extends GetxController {
if (payUser.value == null) {
return;
}
// 判断是否为线下支付
final isOffline = OrderPayDisplayType.isOffline(orderPayDisplayType.value!);
if (isOffline) {
orderType = OrderType.BELOW;
onDiscernUser?.call(payUser.value);
}
await onSubmit?.call(
payUser.value!,
orderType,
@@ -373,25 +400,15 @@ class SelectPayTypeDialogController extends GetxController {
}
// **************************************************************************
// 现金支付 start
// 线下支付 start
// **************************************************************************
Future<void> _dispatchCash() async {
Future<void> _dispatchWalletScanCode() async {
orderPayType.value = OrderPayType.CASH;
orderType = OrderType.BELOW;
payUser.value = ServiceUser(
userId: "-1",
username: "未知用户",
deptId: "-1",
userMobile: "??????",
userAvatar: "",
walletId: "-1",
walletTypeId: "-1",
walletBalance: 1000 * 100,
);
onDiscernUser?.call(payUser.value);
}
// **************************************************************************
// 现金支付 end
// 线下支付 end
// **************************************************************************
// android人脸识别成功回调
@@ -414,6 +431,7 @@ class SelectPayTypeDialogController extends GetxController {
payUser.value = data;
logger.i("|_tag|人脸识别|有网络|,用户信息:|${payUser.toJson()}|");
await SyncUserTool.storageUser(user: payUser.value!);
await _getWalletList();
} else {
// 没有网络去本地数据库查询
final user = await SyncUserTool.storageUserByUserId(event.userId!);
@@ -471,6 +489,31 @@ class SelectPayTypeDialogController extends GetxController {
}
return success.contains(type);
}
/// 获取用户钱包列表
Future<void> _getWalletList() async {
// 如果选择了需要选择钱包的支付方式
if (appSetting.sysType != SysType.SUPERMARKET) {
return;
}
final isSelectWallet = OrderPayDisplayType.isSelectWalletPayType(
orderPayDisplayType.value!,
);
if (!isSelectWallet) return;
try {
if (payUser.value == null) return;
if (AppUserTool.isGenerateExternalUser(payUser.value!)) return;
final userId = payUser.value?.userId;
if (userId == null) return;
final data = await WalletApi.getWalletList({"userId": userId});
if (data == null) throw Error();
userWalletList.value = data;
} catch (error, stack) {
logger.e("|$_tag|获取用户钱包列表,意外的错误error:|$error|stack:|$stack|");
}
}
}
Future<void> selectPayTypeDialog() async {
@@ -480,46 +523,80 @@ Future<void> selectPayTypeDialog() async {
final theme = FTheme.of(Get.context!);
final width = Get.context!.width;
final height = Get.context!.height;
final dialogWidth = width * 0.55;
final dialogHeight = height * 0.7;
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext _) {
return PopScope(
child: FDialog(
direction: Axis.vertical,
title: Text("选择支付方式", style: theme.typography.lg),
body: <Widget>[
Obx(
() => FSelectGroup(
enabled: payTypeC.payUser.value == null,
controller: payTypeC.payTypeRadioC,
style: theme.selectGroupStyle.copyWith(
labelLayoutStyle:
theme.selectGroupStyle.labelLayoutStyle.copyWith(
childPadding: EdgeInsets.symmetric(
vertical: 10.h,
),
),
radioStyle: theme.selectGroupStyle.radioStyle.copyWith(
padding: EdgeInsets.symmetric(
vertical: 10.h,
),
return FDialog(
title:
Text("选择支付方式", style: theme.typography.lg).marginOnly(bottom: 20.h),
style: theme.dialogStyle.copyWith(
insetPadding: EdgeInsets.zero,
maxWidth: dialogWidth,
minWidth: dialogWidth,
horizontalStyle: theme.dialogStyle.horizontalStyle.copyWith(
padding: EdgeInsets.all(20.w),
),
),
body: <Widget>[
Obx(
() => FSelectGroup(
enabled: payTypeC.payUser.value == null,
controller: payTypeC.payTypeRadioC,
style: theme.selectGroupStyle.copyWith(
labelLayoutStyle:
theme.selectGroupStyle.labelLayoutStyle.copyWith(
childPadding: EdgeInsets.symmetric(
vertical: 10.h,
horizontal: 10.w,
),
),
radioStyle: theme.selectGroupStyle.radioStyle.copyWith(
padding: EdgeInsets.symmetric(
vertical: 10.h,
),
),
items: payTypeC.usePayDisplayTypeList
.map<FSelectGroupItem<OrderPayDisplayType>>(
(v) => FSelectGroupItem.radio(
value: v,
label: Text(
v.title,
style: theme.typography.xl,
),
),
)
.toList(),
),
items: payTypeC.usePayDisplayTypeList
.map<FSelectGroupItem<OrderPayDisplayType>>(
(v) => FSelectGroupItem.radio(
value: v,
label: Text(
v.title,
style: theme.typography.xl,
),
),
)
.toList(),
),
).expanded(),
<Widget>[
Obx(
() => AppWalletSelector(
context,
list: payTypeC.userWalletList,
selector: payTypeC.currentWallet.value,
onChange: (wallet) {
payTypeC.currentWallet.value = wallet;
// 设置payUser
final payUser = payTypeC.payUser.value;
if (payUser == null) return;
payUser.walletId = wallet.id;
payUser.walletTypeId = wallet.walletTypeId;
payUser.walletBalance = wallet.balance;
payUser.walletCardNumber = wallet.cardNumber;
payUser.walletIsFreeze = wallet.walletIsFreeze;
},
).width(double.infinity).height(200.h).offstage(
offstage:
!(payTypeC.appSetting.sysType == SysType.SUPERMARKET &&
payTypeC.userWalletList.isNotEmpty &&
OrderPayDisplayType.isSelectWalletPayType(
payTypeC.orderPayDisplayType.value!)),
),
),
SizedBox(height: 20.h),
Obx(
() => Visibility(
visible: payTypeC.payUser.value == null,
@@ -533,45 +610,55 @@ Future<void> selectPayTypeDialog() async {
isLoading: payTypeC.isRecognition.value,
),
),
).center().expanded(),
].toColumn().width(width * 0.7).height(height * 0.7),
actions: [
<Widget>[
Obx(
() => FButton(
label: Text(
payTypeC.payUser.value == null ? "开始识别" : "确定支付",
style: theme.typography.xl.copyWith(
color: theme.colorScheme.secondary,
),
),
onPress: payTypeC.isRecognition.value
? null
: () {
if (payTypeC.payUser.value == null) {
payTypeC.doRecognition();
} else {
payTypeC.doSubmit();
}
},
).flexible(flex: 1),
]
.toColumn()
.paddingAll(5.w)
.decorated(
border: Border.all(
color: theme.colorScheme.primary,
width: 1,
),
).flexible(flex: 1),
SizedBox(width: 20.w),
FButton(
style: FButtonStyle.destructive,
borderRadius: theme.style.borderRadius / 3,
)
.expanded(),
].toRow().width(double.infinity).height(dialogHeight),
actions: [
<Widget>[
Obx(
() => FButton(
label: Text(
"取消",
payTypeC.payUser.value == null ? "开始识别" : "确定支付",
style: theme.typography.xl.copyWith(
color: theme.colorScheme.secondary,
),
),
onPress: () {
payTypeC.doCancel();
},
).flexible(flex: 1),
].toRow(),
],
),
onPress: payTypeC.isRecognition.value
? null
: () {
if (payTypeC.payUser.value == null) {
payTypeC.doRecognition();
} else {
payTypeC.doSubmit();
}
},
),
).flexible(flex: 1),
SizedBox(width: 20.w),
FButton(
style: FButtonStyle.destructive,
label: Text(
"取消",
style: theme.typography.xl.copyWith(
color: theme.colorScheme.secondary,
),
),
onPress: () {
payTypeC.doCancel();
},
).flexible(flex: 1),
].toRow(),
],
);
},
);
@@ -632,11 +719,11 @@ Widget selectPayTypeUser(ServiceUser? user, OrderPayType? payType) {
prefixIcon: FIcon(FAssets.icons.ban),
title: Text('是否冻结', style: textStyle),
details: Text(isFree ? "是" : "否", style: textStyle),
).offstage(offstage: user.walletCardNumber == null),
).offstage(offstage: user.walletIsFreeze == null),
]);
}
return widgets
.toColumn(mainAxisAlignment: MainAxisAlignment.center)
.toColumn(mainAxisAlignment: MainAxisAlignment.start)
.height(double.infinity);
}
@@ -650,10 +737,6 @@ Widget selectPayTypeHint(
String msg = "";
SvgAsset icon = FAssets.icons.bird;
switch (type) {
case OrderPayDisplayType.qrCodeScan:
msg = "$baseMsg,并让用户扫一扫二维码";
icon = FAssets.icons.qrCode;
break;
case OrderPayDisplayType.qrCode:
msg = "$baseMsg,并让用户出示二维码";
icon = FAssets.icons.qrCode;
+1 -1
View File
@@ -35,7 +35,7 @@ Widget appUserInfo(
<Widget>[
Text("姓名:$username", style: style),
<Widget>[
Text("饭卡余额:", style: style),
Text("余额:", style: style),
appPrice(context, balance),
].toRow().offstage(offstage: !visibleMoney),
].toColumn(crossAxisAlignment: CrossAxisAlignment.start),
+7 -5
View File
@@ -167,8 +167,9 @@ class SupermarketOrderController extends GetxController with OrderMixin {
}
// |+|或者|-|点击更改商品数量
void doComputedInputChange(int number, int index) async {
final current = shopCardList[index];
void doComputedInputChange(int number, String productCard) async {
final current = shopCardList
.firstWhere((item) => item.productServiceUniqueCode == productCard);
// 称重商品在购物车就直接删除
if (current.nature == ProductNature.WEIGHT) {
final shopCard = _findShopProductByCode(current.productServiceUniqueCode);
@@ -190,8 +191,9 @@ class SupermarketOrderController extends GetxController with OrderMixin {
}
// |购买商品|点击称重
Future<void> computedPanelWidget(double widget, int i) async {
final current = shopCardList[i];
Future<void> computedPanelWidget(double widget, String productCode) async {
final current = shopCardList
.firstWhere((item) => item.productServiceUniqueCode == productCode);
// 直接查数据库
final skuDao = appC.dataBase.getSupermarketSkuDao;
final targetProduct = await skuDao.getBySkuCode(
@@ -335,7 +337,7 @@ class SupermarketOrderController extends GetxController with OrderMixin {
scanProduct.serviceUniqueCode,
);
if (target != -1) {
await computedPanelWidget(0, target);
await computedPanelWidget(0, scanProduct.serviceUniqueCode);
return;
} else {
// 商品添加到购物车
+8 -4
View File
@@ -250,10 +250,14 @@ class SupermarketOrderPage extends GetView<SupermarketOrderController> {
index: index,
showPlus: current.nature == ProductNature.DEFAULT,
showWidget: current.nature == ProductNature.WEIGHT,
onPlusChange: (number, i) =>
controller.doComputedInputChange(number, i),
onWidgetChange: (widget, i) =>
controller.computedPanelWidget(widget, i),
onPlusChange: (number, i) => controller.doComputedInputChange(
number,
current.productServiceUniqueCode,
),
onWidgetChange: (widget, i) => controller.computedPanelWidget(
widget,
current.productServiceUniqueCode,
),
).marginOnly(bottom: 10.h);
},
),