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

@@ -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),