Browse Source

[new]增加支付宝弹窗扫码支付流程

zk 8 months ago
parent
commit
adb876f2e1

+ 3 - 0
assets/string/base/string.xml

@@ -283,4 +283,7 @@
     <string name="pay_not_connect_store">无法连接到商店</string>
     <string name="pay_not_connect_store">无法连接到商店</string>
     <string name="pay_success_title">支付成功</string>
     <string name="pay_success_title">支付成功</string>
     <string name="pay_success_desc">您的订单已成功支付</string>
     <string name="pay_success_desc">您的订单已成功支付</string>
+    <string name="alipay_qr_code_tips">请使用支付宝扫码支付</string>
+    <string name="wechat_pay_qr_code_tips">请使用微信扫码支付</string>
+    <string name="member_payment_failed">开通失败,请稍后重试</string>
 </resources>
 </resources>

+ 15 - 0
lib/data/bean/goods_bean.dart

@@ -54,4 +54,19 @@ class GoodsBean {
 
 
   factory GoodsBean.fromJson(Map<String, dynamic> json) =>
   factory GoodsBean.fromJson(Map<String, dynamic> json) =>
       _$GoodsBeanFromJson(json);
       _$GoodsBeanFromJson(json);
+
+  GoodsBean copyWith() {
+    return GoodsBean(
+      id,
+      name,
+      level,
+      originalAmount,
+      amount,
+      subscriptionMillis,
+      popular,
+      newcomer,
+      tag,
+      appleGoodsId,
+    );
+  }
 }
 }

+ 4 - 0
lib/data/bean/pay_item_bean.dart

@@ -24,4 +24,8 @@ class PayItemBean {
 
 
   factory PayItemBean.fromJson(Map<String, dynamic> json) =>
   factory PayItemBean.fromJson(Map<String, dynamic> json) =>
       _$PayItemBeanFromJson(json);
       _$PayItemBeanFromJson(json);
+
+  PayItemBean copyWith() {
+    return PayItemBean(id, payMethod, payPlatform, title, isDefaultCheck);
+  }
 }
 }

+ 1 - 0
lib/data/consts/error_code.dart

@@ -20,6 +20,7 @@ class ErrorCode {
   /// 会员服务相关错误码
   /// 会员服务相关错误码
   static const int getMemberFree = 1300; //每位用户只能领取一次试用
   static const int getMemberFree = 1300; //每位用户只能领取一次试用
   static const int isMember = 1301; //您已经是会员了
   static const int isMember = 1301; //您已经是会员了
+  static const int payOrderError = 1004;
 }
 }
 
 
 /// 错误码扩展方法
 /// 错误码扩展方法

+ 37 - 0
lib/data/consts/payment_type.dart

@@ -1,3 +1,5 @@
+import '../../resource/assets.gen.dart';
+
 class PayPlatform {
 class PayPlatform {
   static const int android = 1;
   static const int android = 1;
   static const int apple = 2;
   static const int apple = 2;
@@ -15,3 +17,38 @@ class Currency {
   static const String cny = "CNY";
   static const String cny = "CNY";
   static const String usd = "USD";
   static const String usd = "USD";
 }
 }
+
+class PayWayType {
+  static const int paymentWayWechat = 1;
+  static const int paymentWayWechatScan = 2;
+  static const int paymentWayAlipay = 3;
+  static const int paymentWayAlipayScan = 4;
+
+  static const int unKnown = -1;
+}
+
+String getPaymentIconPath({required int payMethod, required int payPlatform}) {
+  if (payPlatform == 1 && payMethod == 2) {
+    return Assets.images.iconWechatPayment.path;
+  } else if (payPlatform == 4 && payMethod == 2) {
+    return Assets.images.iconWechatScanPayment.path;
+  } else if (payPlatform == 1 && payMethod == 1) {
+    return Assets.images.iconAlipayPayment.path;
+  } else if (payPlatform == 4 && payMethod == 1) {
+    return Assets.images.iconAlipayScanPayment.path;
+  }
+  return '';
+}
+
+int getPayWayType({required int payMethod, required int payPlatform}) {
+  if (payPlatform == 1 && payMethod == 2) {
+    return PayWayType.paymentWayWechat;
+  } else if (payPlatform == 4 && payMethod == 2) {
+    return PayWayType.paymentWayWechatScan;
+  } else if (payPlatform == 1 && payMethod == 1) {
+    return PayWayType.paymentWayAlipay;
+  } else if (payPlatform == 4 && payMethod == 1) {
+    return PayWayType.paymentWayAlipayScan;
+  }
+  return PayWayType.unKnown;
+}

+ 7 - 1
lib/data/repositories/member_repository.dart

@@ -1,8 +1,10 @@
 import 'package:injectable/injectable.dart';
 import 'package:injectable/injectable.dart';
 import 'package:location/base/app_base_request.dart';
 import 'package:location/base/app_base_request.dart';
 import 'package:location/data/api/atmob_api.dart';
 import 'package:location/data/api/atmob_api.dart';
+import 'package:location/data/repositories/account_repository.dart';
 import 'package:location/utils/http_handler.dart';
 import 'package:location/utils/http_handler.dart';
 
 
+import '../../utils/payment_status_manager.dart';
 import '../api/request/order_status_request.dart';
 import '../api/request/order_status_request.dart';
 import '../api/request/submit_and_request_pay_request.dart';
 import '../api/request/submit_and_request_pay_request.dart';
 import '../api/response/item_list_response.dart';
 import '../api/response/item_list_response.dart';
@@ -11,8 +13,9 @@ import '../api/response/request_pay_response.dart';
 @lazySingleton
 @lazySingleton
 class MemberRepository {
 class MemberRepository {
   final AtmobApi atmobApi;
   final AtmobApi atmobApi;
+  final AccountRepository accountRepository;
 
 
-  MemberRepository(this.atmobApi);
+  MemberRepository(this.atmobApi, this.accountRepository);
 
 
   Future<int> memberTrial() {
   Future<int> memberTrial() {
     return atmobApi
     return atmobApi
@@ -42,6 +45,9 @@ class MemberRepository {
         .orderStatus(OrderStatusRequest(outTradeNo, receiptData))
         .orderStatus(OrderStatusRequest(outTradeNo, receiptData))
         .then(HttpHandler.handle(false))
         .then(HttpHandler.handle(false))
         .then((data) {
         .then((data) {
+      if (data.payStatus == PaymentStatus.payStatusSuccess) {
+        accountRepository.refreshMemberStatus();
+      }
       return data.payStatus;
       return data.payStatus;
     });
     });
   }
   }

+ 11 - 12
lib/di/get_it.config.dart

@@ -72,19 +72,12 @@ extension GetItInjectableX on _i174.GetIt {
         () => _i850.ContactRepository(gh<_i243.AtmobApi>()));
         () => _i850.ContactRepository(gh<_i243.AtmobApi>()));
     gh.lazySingleton<_i1053.FriendsRepository>(
     gh.lazySingleton<_i1053.FriendsRepository>(
         () => _i1053.FriendsRepository(gh<_i243.AtmobApi>()));
         () => _i1053.FriendsRepository(gh<_i243.AtmobApi>()));
-    gh.lazySingleton<_i814.MemberRepository>(
-        () => _i814.MemberRepository(gh<_i243.AtmobApi>()));
     gh.lazySingleton<_i791.MessageRepository>(
     gh.lazySingleton<_i791.MessageRepository>(
         () => _i791.MessageRepository(gh<_i243.AtmobApi>()));
         () => _i791.MessageRepository(gh<_i243.AtmobApi>()));
     gh.lazySingleton<_i240.TrackRepository>(
     gh.lazySingleton<_i240.TrackRepository>(
         () => _i240.TrackRepository(gh<_i243.AtmobApi>()));
         () => _i240.TrackRepository(gh<_i243.AtmobApi>()));
     gh.lazySingleton<_i983.UrgentContactRepository>(
     gh.lazySingleton<_i983.UrgentContactRepository>(
         () => _i983.UrgentContactRepository(gh<_i243.AtmobApi>()));
         () => _i983.UrgentContactRepository(gh<_i243.AtmobApi>()));
-    gh.lazySingleton<_i779.PaymentStatusManager>(
-        () => _i779.PaymentStatusManager(
-              gh<_i814.MemberRepository>(),
-              gh<_i20.AccountRepository>(),
-            ));
     gh.factory<_i1008.LoginController>(
     gh.factory<_i1008.LoginController>(
         () => _i1008.LoginController(gh<_i20.AccountRepository>()));
         () => _i1008.LoginController(gh<_i20.AccountRepository>()));
     gh.factory<_i489.NewsController>(
     gh.factory<_i489.NewsController>(
@@ -115,11 +108,6 @@ extension GetItInjectableX on _i174.GetIt {
           gh<_i983.UrgentContactRepository>(),
           gh<_i983.UrgentContactRepository>(),
           gh<_i825.ConfigRepository>(),
           gh<_i825.ConfigRepository>(),
         ));
         ));
-    gh.factory<_i269.MemberController>(() => _i269.MemberController(
-          gh<_i20.AccountRepository>(),
-          gh<_i814.MemberRepository>(),
-          gh<_i779.PaymentStatusManager>(),
-        ));
     gh.factory<_i955.AddUrgentContactController>(
     gh.factory<_i955.AddUrgentContactController>(
         () => _i955.AddUrgentContactController(
         () => _i955.AddUrgentContactController(
               gh<_i983.UrgentContactRepository>(),
               gh<_i983.UrgentContactRepository>(),
@@ -134,11 +122,22 @@ extension GetItInjectableX on _i174.GetIt {
         () => _i897.AddFriendDialogController(gh<_i1053.FriendsRepository>()));
         () => _i897.AddFriendDialogController(gh<_i1053.FriendsRepository>()));
     gh.factory<_i492.FriendSettingController>(
     gh.factory<_i492.FriendSettingController>(
         () => _i492.FriendSettingController(gh<_i1053.FriendsRepository>()));
         () => _i492.FriendSettingController(gh<_i1053.FriendsRepository>()));
+    gh.lazySingleton<_i814.MemberRepository>(() => _i814.MemberRepository(
+          gh<_i243.AtmobApi>(),
+          gh<_i20.AccountRepository>(),
+        ));
     gh.factory<_i732.MineController>(() => _i732.MineController(
     gh.factory<_i732.MineController>(() => _i732.MineController(
           gh<_i20.AccountRepository>(),
           gh<_i20.AccountRepository>(),
           gh<_i825.ConfigRepository>(),
           gh<_i825.ConfigRepository>(),
           gh<_i814.MemberRepository>(),
           gh<_i814.MemberRepository>(),
         ));
         ));
+    gh.lazySingleton<_i779.PaymentStatusManager>(
+        () => _i779.PaymentStatusManager(gh<_i814.MemberRepository>()));
+    gh.factory<_i269.MemberController>(() => _i269.MemberController(
+          gh<_i20.AccountRepository>(),
+          gh<_i814.MemberRepository>(),
+          gh<_i779.PaymentStatusManager>(),
+        ));
     return this;
     return this;
   }
   }
 }
 }

+ 121 - 0
lib/dialog/alipay_qr_code_dialog.dart

@@ -0,0 +1,121 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
+import 'package:get/get.dart';
+import 'package:location/resource/assets.gen.dart';
+import 'package:location/resource/colors.gen.dart';
+import 'package:location/resource/string.gen.dart';
+import 'package:webview_flutter/webview_flutter.dart';
+
+class AlipayQrCodeDialog {
+  static const String _tag = 'AlipayQrCodeDialog';
+
+  static void show(
+      {required String qrCodeHtml,
+      required String orderId,
+      VoidCallback? onDismiss,
+      VoidCallback? onCloseCallback,
+      VoidCallback? loadSuccessCallback}) {
+    SmartDialog.show(
+        tag: _tag,
+        onDismiss: onDismiss,
+        backDismiss: false,
+        builder: (_) {
+          return AlipayQrCodeView(
+              qrCodeHtml: qrCodeHtml,
+              orderId: orderId,
+              onCloseCallback: onCloseCallback,
+              loadSuccessCallback: loadSuccessCallback);
+        },
+        clickMaskDismiss: false);
+  }
+
+  static void dismiss() {
+    SmartDialog.dismiss(tag: _tag);
+  }
+}
+
+class AlipayQrCodeView extends Dialog {
+  final String qrCodeHtml;
+  final String orderId;
+  VoidCallback? loadSuccessCallback;
+  VoidCallback? onCloseCallback;
+
+  final WebViewController webViewController = WebViewController();
+
+  AlipayQrCodeView(
+      {super.key,
+      required this.qrCodeHtml,
+      required this.orderId,
+      this.onCloseCallback,
+      this.loadSuccessCallback});
+
+  @override
+  Widget build(BuildContext context) {
+    return IntrinsicHeight(
+      child: Column(
+        children: [
+          Container(
+            padding: EdgeInsets.all(26.w),
+            decoration: BoxDecoration(
+              color: Colors.white,
+              borderRadius: BorderRadius.circular(10.w),
+            ),
+            child: Column(
+              children: [
+                SizedBox(
+                  width: 220.w,
+                  height: 220.w,
+                  child: WebViewWidget(
+                    controller: webViewController
+                      ..loadHtmlString(getHtmlTemplate())
+                      ..setJavaScriptMode(JavaScriptMode.unrestricted)
+                      ..setNavigationDelegate(NavigationDelegate(
+                        onPageFinished: (String url) {
+                          // 使用 CSS 放大页面内容
+                          final scaleFactor = Get.width / 45.w;
+                          webViewController.runJavaScript('''
+                         document.body.style.transform = "scale($scaleFactor)";
+                         document.body.style.transformOrigin = "0 0";  
+                         
+                        document.body.style.touchAction = 'none';
+                        document.documentElement.style.overscrollBehavior = 'none';           
+                      ''');
+                          loadSuccessCallback?.call();
+                          loadSuccessCallback = null;
+                        },
+                      )),
+                  ),
+                ),
+                SizedBox(height: 16.w),
+                Text(StringName.alipayQrCodeTips,
+                    style: TextStyle(fontSize: 14.sp, color: ColorName.black90))
+              ],
+            ),
+          ),
+          SizedBox(height: 20.w),
+          GestureDetector(
+              onTap: () {
+                onCloseCallback?.call();
+                AlipayQrCodeDialog.dismiss();
+              },
+              child: Assets.images.iconMemberRetainClose
+                  .image(width: 32.w, height: 32.w))
+        ],
+      ),
+    );
+  }
+
+  String getHtmlTemplate() {
+    return '''
+    <!DOCTYPE html><html lang=\"en\">
+      <head><meta charset=\"UTF-8\"/>
+        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"/>
+        <title>Alipay QR Code</title>
+      </head>
+      <body>$qrCodeHtml</body>
+     </html>
+ 
+     ''';
+  }
+}

+ 95 - 54
lib/module/member/member_controller.dart

@@ -12,6 +12,7 @@ import 'package:location/data/bean/goods_bean.dart';
 import 'package:location/data/bean/pay_item_bean.dart';
 import 'package:location/data/bean/pay_item_bean.dart';
 import 'package:location/data/repositories/account_repository.dart';
 import 'package:location/data/repositories/account_repository.dart';
 import 'package:location/data/repositories/member_repository.dart';
 import 'package:location/data/repositories/member_repository.dart';
+import 'package:location/dialog/alipay_qr_code_dialog.dart';
 import 'package:location/handler/error_handler.dart';
 import 'package:location/handler/error_handler.dart';
 import 'package:location/module/login/login_page.dart';
 import 'package:location/module/login/login_page.dart';
 import 'package:location/resource/assets.gen.dart';
 import 'package:location/resource/assets.gen.dart';
@@ -239,7 +240,7 @@ class MemberController extends BaseController implements PaymentStatusCallback {
     });
     });
   }
   }
 
 
-  void onBuyClick() async {
+  void onBuyClick() {
     if (selectedGoods == null) {
     if (selectedGoods == null) {
       ToastUtil.show(StringName.memberPleaseChoiceGoods);
       ToastUtil.show(StringName.memberPleaseChoiceGoods);
       return;
       return;
@@ -254,60 +255,108 @@ class MemberController extends BaseController implements PaymentStatusCallback {
     int goodsId = buyGoods.id;
     int goodsId = buyGoods.id;
     int payPlatform = buyPayWay.payPlatform;
     int payPlatform = buyPayWay.payPlatform;
     int payMethod = buyPayWay.payMethod;
     int payMethod = buyPayWay.payMethod;
-    LoadingDialog.show(StringName.payLoading);
+    int payWayType =
+        getPayWayType(payMethod: payMethod, payPlatform: payPlatform);
 
 
-    try {
-      RequestPayResponse response = await memberRepository.submitAndRequestPay(
-          goodsId: goodsId, payPlatform: payPlatform, payMethod: payMethod);
-      dynamic payInfo;
-      String outTradeNo = response.outTradeNo;
-      if (payPlatform == PayPlatform.android) {
-        if (payMethod == PayMethod.alipay) {
-          payInfo = AliPayInfo(response.alipayOrderString!);
-        } else if (payMethod == PayMethod.wechat) {
-          WechatPaymentSignBean bean =
-              WechatPaymentSignBean.stringToBean(response.wechatPayPrepayJson!);
-          payInfo = WechatPayInfo(
-              appId: bean.appId,
-              partnerId: bean.partnerId,
-              prepayId: bean.prepayId,
-              package: bean.package,
-              noncestr: bean.nonceStr,
-              timestamp: bean.timeStamp,
-              sign: bean.sign);
-        }
+    LoadingDialog.show(StringName.payLoading);
+    memberRepository
+        .submitAndRequestPay(
+            goodsId: goodsId, payPlatform: payPlatform, payMethod: payMethod)
+        .then((response) {
+      if (payWayType == PayWayType.paymentWayWechat) {
+        _onWeChatPay(response.outTradeNo, response.wechatPayPrepayJson!,
+            payMethod, buyGoods, buyPayWay);
+      } else if (payWayType == PayWayType.paymentWayWechatScan) {
+        _onWechatScanPay();
+      } else if (payWayType == PayWayType.paymentWayAlipay) {
+        _onAliPay(response.outTradeNo, response.alipayOrderString!, payMethod,
+            buyGoods, buyPayWay);
+      } else if (payWayType == PayWayType.paymentWayAlipayScan) {
+        _onAliScanPay(response.outTradeNo, response.alipayQrcodeHtml!,
+            buyPayWay, buyGoods);
+      } else {
+        ToastUtil.show(StringName.payNotSupport);
       }
       }
-      AgilePay.startPay(payInfo, success: (String? result) {
-        LoadingDialog.show(StringName.payQuerypayState);
-        checkPaymentStatus(outTradeNo, buyPayWay, buyGoods,
-            receiptData: result);
-        Future.delayed(const Duration(seconds: 30), () {
-          LoadingDialog.hide();
-        });
-      }, payError: (int error, String? errorMessage) {
-        debugPrint('zk---payError: $error, $errorMessage');
-        errorPayToast(error);
-        errorEventReport(payMethod);
-        LoadingDialog.hide();
-      }, error: (int errno, String? error) {
-        debugPrint('zk---error: $errno, $error');
-        errorPayToast(errno);
-        errorEventReport(payMethod);
-        LoadingDialog.hide();
-      });
-    } catch (error) {
-      LoadingDialog.hide();
+    }).catchError((error) {
       if (error is ServerErrorException) {
       if (error is ServerErrorException) {
-        if (error.code == ErrorCode.noLoginError) {
+        if (error.code == ErrorCode.payOrderError) {
+          refreshMemberData();
+          ToastUtil.show(error.message);
+        } else if (error.code == ErrorCode.noLoginError) {
           ToastUtil.show(StringName.accountNoLogin);
           ToastUtil.show(StringName.accountNoLogin);
           LoginPage.start();
           LoginPage.start();
         } else {
         } else {
-          ErrorHandler.toastError(error);
+          ToastUtil.show(error.message);
         }
         }
       } else {
       } else {
-        ToastUtil.show(StringName.payError);
+        ToastUtil.show(StringName.memberPaymentFailed);
       }
       }
-    }
+    }).whenComplete(() {
+      LoadingDialog.hide();
+    });
+  }
+
+  void _onAliScanPay(String outTradeNo, String qrHtml, PayItemBean paymentWay,
+      GoodsBean goodsBean) {
+    AlipayQrCodeDialog.show(
+        qrCodeHtml: qrHtml,
+        orderId: outTradeNo,
+        loadSuccessCallback: () {
+          checkPaymentStatus(outTradeNo, paymentWay, goodsBean);
+        },
+        onCloseCallback: () async {
+          //关闭后再持续查询几秒
+          CustomLoadingDialog.show();
+          await Future.delayed(Duration(seconds: 4));
+          paymentStatusManager.removePollingSubscription(outTradeNo);
+          CustomLoadingDialog.hide();
+        });
+  }
+
+  void checkPaymentStatus(
+      String orderNo, PayItemBean paymentWay, GoodsBean goodsBean,
+      {String? receiptData}) {
+    paymentStatusManager.registerPaymentSuccessCallback(orderNo, this);
+    paymentStatusManager.checkPaymentStatus(orderNo, paymentWay, goodsBean,
+        receiptData: receiptData);
+  }
+
+  void _onWeChatPay(String outTradeNo, String payJson, int payMethod,
+      GoodsBean buyGoods, PayItemBean buyPayWay) {
+    final bean = WechatPaymentSignBean.stringToBean(payJson);
+    final payInfo = WechatPayInfo(
+        appId: bean.appId,
+        partnerId: bean.partnerId,
+        prepayId: bean.prepayId,
+        package: bean.package,
+        noncestr: bean.nonceStr,
+        timestamp: bean.timeStamp,
+        sign: bean.sign);
+    requestSdkPay(payInfo, outTradeNo, payMethod, buyGoods, buyPayWay);
+  }
+
+  void _onAliPay(String outTradeNo, String payJson, int payMethod,
+      GoodsBean buyGoods, PayItemBean buyPayWay) {
+    final payInfo = AliPayInfo(payJson);
+    requestSdkPay(payInfo, outTradeNo, payMethod, buyGoods, buyPayWay);
+  }
+
+  void _onWechatScanPay() {}
+
+  void requestSdkPay(dynamic payInfo, String outTradeNo, int payMethod,
+      GoodsBean buyGoods, PayItemBean buyPayWay) {
+    AgilePay.startPay(payInfo, success: (String? result) {
+      LoadingDialog.show(StringName.payQuerypayState);
+      checkPaymentStatus(outTradeNo, buyPayWay, buyGoods, receiptData: result);
+    }, payError: (int error, String? errorMessage) {
+      debugPrint('zk---payError: $error, $errorMessage');
+      errorPayToast(error);
+      errorEventReport(payMethod);
+    }, error: (int errno, String? error) {
+      debugPrint('zk---error: $errno, $error');
+      errorPayToast(errno);
+      errorEventReport(payMethod);
+    });
   }
   }
 
 
   void errorEventReport(int payMethod) {
   void errorEventReport(int payMethod) {
@@ -334,14 +383,6 @@ class MemberController extends BaseController implements PaymentStatusCallback {
     }
     }
   }
   }
 
 
-  void checkPaymentStatus(
-      String orderNo, PayItemBean paymentWay, GoodsBean goodsBean,
-      {String? receiptData}) {
-    paymentStatusManager.registerPaymentSuccessCallback(orderNo, this);
-    paymentStatusManager.checkPaymentStatus(orderNo, paymentWay, goodsBean,
-        receiptData: receiptData);
-  }
-
   @override
   @override
   void onClose() {
   void onClose() {
     super.onClose();
     super.onClose();

+ 1 - 0
lib/module/member/member_page.dart

@@ -14,6 +14,7 @@ import 'package:location/utils/project_expand.dart';
 import 'package:location/widget/auto_scroll_list_view.dart';
 import 'package:location/widget/auto_scroll_list_view.dart';
 import '../../data/bean/member_status_info.dart';
 import '../../data/bean/member_status_info.dart';
 import '../../data/bean/pay_item_bean.dart';
 import '../../data/bean/pay_item_bean.dart';
+import '../../data/consts/payment_type.dart';
 import '../../resource/fonts.gen.dart';
 import '../../resource/fonts.gen.dart';
 import '../../resource/string.gen.dart';
 import '../../resource/string.gen.dart';
 import '../../router/app_pages.dart';
 import '../../router/app_pages.dart';

+ 8 - 0
lib/resource/string.gen.dart

@@ -236,6 +236,11 @@ class StringName {
       'pay_not_connect_store'.tr; // 无法连接到商店
       'pay_not_connect_store'.tr; // 无法连接到商店
   static final String paySuccessTitle = 'pay_success_title'.tr; // 支付成功
   static final String paySuccessTitle = 'pay_success_title'.tr; // 支付成功
   static final String paySuccessDesc = 'pay_success_desc'.tr; // 您的订单已成功支付
   static final String paySuccessDesc = 'pay_success_desc'.tr; // 您的订单已成功支付
+  static final String alipayQrCodeTips = 'alipay_qr_code_tips'.tr; // 请使用支付宝扫码支付
+  static final String wechatPayQrCodeTips =
+      'wechat_pay_qr_code_tips'.tr; // 请使用微信扫码支付
+  static final String memberPaymentFailed =
+      'member_payment_failed'.tr; // 开通失败,请稍后重试
 }
 }
 class StringMultiSource {
 class StringMultiSource {
   StringMultiSource._();
   StringMultiSource._();
@@ -471,6 +476,9 @@ class StringMultiSource {
       'pay_not_connect_store': '无法连接到商店',
       'pay_not_connect_store': '无法连接到商店',
       'pay_success_title': '支付成功',
       'pay_success_title': '支付成功',
       'pay_success_desc': '您的订单已成功支付',
       'pay_success_desc': '您的订单已成功支付',
+      'alipay_qr_code_tips': '请使用支付宝扫码支付',
+      'wechat_pay_qr_code_tips': '请使用微信扫码支付',
+      'member_payment_failed': '开通失败,请稍后重试',
     },
     },
   };
   };
 }
 }

+ 0 - 12
lib/utils/common_util.dart

@@ -70,15 +70,3 @@ void copyToClipboard(String content) {
   Clipboard.setData(ClipboardData(text: content));
   Clipboard.setData(ClipboardData(text: content));
 }
 }
 
 
-String getPaymentIconPath({required int payMethod, required int payPlatform}) {
-  if (payPlatform == 1 && payMethod == 2) {
-    return Assets.images.iconWechatPayment.path;
-  } else if (payPlatform == 4 && payMethod == 2) {
-    return Assets.images.iconWechatScanPayment.path;
-  } else if (payPlatform == 1 && payMethod == 1) {
-    return Assets.images.iconAlipayPayment.path;
-  } else if (payPlatform == 4 && payMethod == 1) {
-    return Assets.images.iconAlipayScanPayment.path;
-  }
-  return '';
-}

+ 43 - 32
lib/utils/payment_status_manager.dart

@@ -2,19 +2,14 @@ import 'package:flutter/cupertino.dart';
 import 'package:injectable/injectable.dart';
 import 'package:injectable/injectable.dart';
 import 'package:location/data/bean/goods_bean.dart';
 import 'package:location/data/bean/goods_bean.dart';
 import 'package:location/data/bean/pay_item_bean.dart';
 import 'package:location/data/bean/pay_item_bean.dart';
-import 'package:location/data/repositories/account_repository.dart';
 import 'package:location/data/repositories/member_repository.dart';
 import 'package:location/data/repositories/member_repository.dart';
 import 'package:synchronized/synchronized.dart';
 import 'package:synchronized/synchronized.dart';
 
 
 import '../handler/event_handler.dart';
 import '../handler/event_handler.dart';
 import 'async_util.dart';
 import 'async_util.dart';
 
 
-@lazySingleton
-class PaymentStatusManager {
-  final MemberRepository memberRepository;
-  final AccountRepository accountRepository;
-
-  PaymentStatusManager(this.memberRepository, this.accountRepository);
+class PaymentStatus {
+  PaymentStatus._();
 
 
   //订单状态
   //订单状态
   //0-查询失败,继续轮询
   //0-查询失败,继续轮询
@@ -27,6 +22,13 @@ class PaymentStatusManager {
   static const int payStatusSuccess = 2;
   static const int payStatusSuccess = 2;
   static const int payStatusClose = 3;
   static const int payStatusClose = 3;
   static const int payStatusRefund = 4;
   static const int payStatusRefund = 4;
+}
+
+@lazySingleton
+class PaymentStatusManager {
+  final MemberRepository memberRepository;
+
+  PaymentStatusManager(this.memberRepository);
 
 
   final Map<String, PaymentStatusCallback> callbackMap = {};
   final Map<String, PaymentStatusCallback> callbackMap = {};
   final Map<String, CancelableFuture> pollingSubscriptionMap = {};
   final Map<String, CancelableFuture> pollingSubscriptionMap = {};
@@ -38,29 +40,17 @@ class PaymentStatusManager {
     await _lock.synchronized(() async {
     await _lock.synchronized(() async {
       pollingSubscriptionMap[orderNo]?.cancel();
       pollingSubscriptionMap[orderNo]?.cancel();
       debugPrint('开始轮询支付状态: orderNo = $orderNo');
       debugPrint('开始轮询支付状态: orderNo = $orderNo');
-      CancelableFuture orderFuture = AsyncUtil.retryWithExponentialBackoff(
-          () {
-            return memberRepository
-                .orderStatus(orderNo, receiptData: receiptData)
-                .then((status) {
-              if (status == payStatusSuccess) {
-                return true;
-              } else {
-                throw PaymentStatusException(status);
-              }
-            });
-          },
-          10,
-          predicate: (error) {
-            if (error is PaymentStatusException) {
-              return error.status == payStatusFail ||
-                  error.status == payStatusUnpaid;
-            }
-            return true;
-          });
-      orderFuture.then((data) async {
+      CancelableFuture<int> orderFuture = AsyncUtil.retry(
+          () => _queryOrderStatus(orderNo, receiptData: receiptData),
+          Duration(seconds: 2), predicate: (error) {
+        if (error is PaymentStatusException) {
+          return error.status == PaymentStatus.payStatusFail ||
+              error.status == PaymentStatus.payStatusUnpaid;
+        }
+        return true;
+      }, maxRetry: 50);
+      orderFuture.then((status) async {
         debugPrint('支付成功: orderNo = $orderNo');
         debugPrint('支付成功: orderNo = $orderNo');
-        accountRepository.refreshMemberStatus();
         await _lock.synchronized(() {
         await _lock.synchronized(() {
           callbackMap[orderNo]
           callbackMap[orderNo]
               ?.onPaymentSuccess(orderNo, paymentWay, storeItemBean);
               ?.onPaymentSuccess(orderNo, paymentWay, storeItemBean);
@@ -68,13 +58,27 @@ class PaymentStatusManager {
         });
         });
         reportPaySuccess(storeItemBean.amount, orderNo, storeItemBean.name,
         reportPaySuccess(storeItemBean.amount, orderNo, storeItemBean.name,
             paymentWay.payMethod);
             paymentWay.payMethod);
-      }).catchError((error) {
+      }).catchError((error) async {
+        await _lock.synchronized(() {
+          callbackMap.remove(orderNo);
+        });
         debugPrint('支付失败: orderNo = $orderNo, error = $error');
         debugPrint('支付失败: orderNo = $orderNo, error = $error');
       });
       });
       pollingSubscriptionMap[orderNo] = orderFuture;
       pollingSubscriptionMap[orderNo] = orderFuture;
     });
     });
   }
   }
 
 
+  Future<int> _queryOrderStatus(String orderNo, {String? receiptData}) {
+    return memberRepository
+        .orderStatus(orderNo, receiptData: receiptData)
+        .then((status) async {
+      if (status == PaymentStatus.payStatusSuccess) {
+        return status;
+      }
+      throw PaymentStatusException(status);
+    });
+  }
+
   void reportPaySuccess(
   void reportPaySuccess(
       int price, String orderId, String itemName, int paymentWay) {
       int price, String orderId, String itemName, int paymentWay) {
     EventHandler.reportPay(price, orderId, itemName, paymentWay);
     EventHandler.reportPay(price, orderId, itemName, paymentWay);
@@ -83,9 +87,10 @@ class PaymentStatusManager {
   void checkPaymentStatus(
   void checkPaymentStatus(
       String orderNo, PayItemBean paymentWay, GoodsBean storeItemBean,
       String orderNo, PayItemBean paymentWay, GoodsBean storeItemBean,
       {String? receiptData}) {
       {String? receiptData}) {
+    final way = paymentWay.copyWith();
+    final goods = storeItemBean.copyWith();
     // recordKeyInfoToDisk(orderNo, paymentWay, storeItemBean);
     // recordKeyInfoToDisk(orderNo, paymentWay, storeItemBean);
-    _startCheckPolling(orderNo, paymentWay, storeItemBean,
-        receiptData: receiptData);
+    _startCheckPolling(orderNo, way, goods, receiptData: receiptData);
   }
   }
 
 
   void registerPaymentSuccessCallback(
   void registerPaymentSuccessCallback(
@@ -100,6 +105,12 @@ class PaymentStatusManager {
       callbackMap.removeWhere((key, value) => value == callback);
       callbackMap.removeWhere((key, value) => value == callback);
     });
     });
   }
   }
+
+  void removePollingSubscription(String orderNo) {
+    pollingSubscriptionMap[orderNo]?.cancel();
+    pollingSubscriptionMap.remove(orderNo);
+    callbackMap.remove(orderNo);
+  }
 }
 }
 
 
 class PaymentStatusException implements Exception {
 class PaymentStatusException implements Exception {

+ 1 - 1
plugins/flutter_qiyu/android/src/main/java/org/leanflutter/plugins/flutter_qiyu/FlutterQiyuPlugin.java

@@ -151,9 +151,9 @@ public class FlutterQiyuPlugin implements FlutterPlugin, MethodCallHandler {
     }
     }
 
 
     private void registerApp(String appKey, String appName) {
     private void registerApp(String appKey, String appName) {
-        Unicorn.initSdk();
         config(context, appKey);
         config(context, appKey);
         Unicorn.addUnreadCountChangeListener(unreadCountChangeListener, true);
         Unicorn.addUnreadCountChangeListener(unreadCountChangeListener, true);
+        Unicorn.initSdk();
     }
     }
 
 
     private void openServiceWindow(MethodCall call) {
     private void openServiceWindow(MethodCall call) {