Browse Source

feat(payment): 添加支付功能多语言支持并优化支付控制器

- 为支付功能添加简体中文、繁体中文和英文的翻译字符串
- 重构支付控制器和商品基础控制器,使用翻译键替代硬编码文本
- 更新支付视图,使界面文本支持多语言切换
- 在.gitignore中添加.qoder目录忽略规则
weicu
lxm 7 months ago
parent
commit
6ea14d0cc4
  1. 1
      .gitignore
  2. 63
      lib/core/translations/language/en_us.dart
  3. 59
      lib/core/translations/language/zh_cn.dart
  4. 59
      lib/core/translations/language/zh_hk.dart
  5. 59
      lib/core/translations/language/zh_tw.dart
  6. 92
      lib/modules/goods/controllers/goods_base_controller.dart
  7. 48
      lib/modules/payment/controllers/payment_controller.dart
  8. 55
      lib/modules/payment/views/payment_view.dart

1
.gitignore

@ -222,4 +222,5 @@ fastlane/readme.md
.trae/rules/project_rules.md
.augment/rules/imported/project_rules.md
.kiro/
.qoder/
ios/Runner.xcodeproj/project.pbxproj

63
lib/core/translations/language/en_us.dart

@ -241,6 +241,69 @@ const Map<String, String> enUS = {
'totalQuota': 'Total Quota',
'remaining': 'Remaining',
'featureDescription': 'Feature Description',
'paymentSuccess': 'Payment successful',
'paymentFailed': 'Payment failed',
'gotIt': 'Got it',
'paymentFailedTryAgain': 'Payment failed. Please try again.',
'selectPaymentMethod': 'Select payment method',
'wechatPay': 'WeChat Pay',
'alipayPay': 'Alipay',
'paypalPay': 'PayPal',
'appleIap': 'Apple IAP',
'googleIap': 'Google IAP',
'wechatOrderCreateFailed': 'Failed to create WeChat order',
'alipayOrderCreateFailed': 'Failed to create Alipay order',
'appleOrderCreateFailed': 'Failed to create Apple order',
'googleOrderCreateFailed': 'Failed to create Google order',
'paypalOrderCreateFailed': 'Failed to create PayPal order',
'paymentException': 'Payment exception',
'paymentLaunchFailed': 'Payment launch failed',
'paymentExceptionWithError': 'Payment exception: @error',
'paymentProcessingCheckLater':
'Your order is being processed. Please check later.',
'paymentResultQueryException': 'Failed to query payment result: @error',
'orderConfirmedQuotaRefreshed':
'Order confirmed. Your quota has been refreshed.',
'paymentCompletedConfirming': 'Payment completed. Confirming…',
'paymentCancelled': 'Payment cancelled',
'paypalOpenedCompleteInBrowser':
'PayPal opened. Please complete the payment in your browser.',
'paypalOpenFailed': 'Unable to open PayPal payment page',
'paymentTestTitle': 'Payment Test',
'paymentTestOrderInfo': 'Test Order Info',
'paymentTestProductId': 'Product ID',
'paymentTestProductDescription': 'Product description',
'paymentTestWechatDescription': 'WeChat payment test',
'paymentTestAlipayDescription': 'Alipay payment test',
'paymentTestAmount': 'Amount',
'paymentTestSelectAmount': 'Select test amount',
'paying': 'Paying...',
'wechatPayWithAmount': 'WeChat Pay ¥@amount',
'alipayPayWithAmount': 'Alipay ¥@amount',
'paymentStatusTitle': 'Payment status',
'errorInfoWithMessage': 'Error: @message',
'retest': 'Retest',
'paymentTestInstructionsTitle': 'Instructions',
'paymentTestInstructionsContent':
'1. Select a test amount (recommended: ¥0.01)\n'
'2. Tap the "WeChat Pay" button\n'
'3. The app will invoke the WeChat Pay SDK\n'
'4. Complete the payment in WeChat\n'
'5. Return to the app to view the result\n\n'
'Note: This is a test environment. No real charge will occur.',
'startingWechatPayment': 'Starting WeChat Pay...',
'startingAlipayPayment': 'Starting Alipay...',
'wechatPaymentSuccess': 'WeChat Pay successful!',
'wechatPaymentFailed': 'WeChat Pay failed',
'wechatPaymentLaunchFailed': 'Failed to launch WeChat Pay',
'cannotLaunchWechatPayment': 'Unable to launch WeChat Pay',
'wechatPaymentException': 'WeChat Pay exception',
'wechatPaymentTestCompleted': 'WeChat Pay test completed',
'alipayPaymentSuccess': 'Alipay successful!',
'alipayPaymentFailed': 'Alipay failed',
'alipayPaymentLaunchFailed': 'Failed to launch Alipay',
'cannotLaunchAlipayPayment': 'Unable to launch Alipay',
'alipayPaymentException': 'Alipay exception',
// AI 功能卡片
'musicAndRecommendation': 'Music & Recommendation',
'navigationAndRoutes': 'Navigation & Routes',

59
lib/core/translations/language/zh_cn.dart

@ -232,6 +232,65 @@ const Map<String, String> zhCN = {
'totalQuota': '总额度',
'remaining': '剩余',
'featureDescription': '功能说明',
'paymentSuccess': '支付成功',
'paymentFailed': '支付失败',
'gotIt': '知道了',
'paymentFailedTryAgain': '支付失败,请重试',
'selectPaymentMethod': '选择支付方式',
'wechatPay': '微信支付',
'alipayPay': '支付宝支付',
'paypalPay': 'PayPal',
'appleIap': 'Apple 内购',
'googleIap': 'Google 内购',
'wechatOrderCreateFailed': '创建微信订单失败',
'alipayOrderCreateFailed': '创建支付宝订单失败',
'appleOrderCreateFailed': '创建 Apple 订单失败',
'googleOrderCreateFailed': '创建 Google 订单失败',
'paypalOrderCreateFailed': '创建 PayPal 订单失败',
'paymentException': '支付异常',
'paymentLaunchFailed': '支付启动失败',
'paymentExceptionWithError': '支付异常: @error',
'paymentProcessingCheckLater': '订单处理中,请稍后查看。',
'paymentResultQueryException': '查询支付结果异常: @error',
'orderConfirmedQuotaRefreshed': '订单已确认,额度已刷新',
'paymentCompletedConfirming': '支付完成,正在确认',
'paymentCancelled': '已取消支付',
'paypalOpenedCompleteInBrowser': '已打开 PayPal,请在浏览器完成支付',
'paypalOpenFailed': '无法打开 PayPal 支付页面',
'paymentTestTitle': '支付测试',
'paymentTestOrderInfo': '测试订单信息',
'paymentTestProductId': '商品ID',
'paymentTestProductDescription': '商品描述',
'paymentTestWechatDescription': '微信支付测试',
'paymentTestAlipayDescription': '支付宝支付测试',
'paymentTestAmount': '支付金额',
'paymentTestSelectAmount': '选择测试金额',
'paying': '支付中...',
'wechatPayWithAmount': '微信支付 ¥@amount',
'alipayPayWithAmount': '支付宝支付 ¥@amount',
'paymentStatusTitle': '支付状态',
'errorInfoWithMessage': '错误信息: @message',
'retest': '重新测试',
'paymentTestInstructionsTitle': '使用说明',
'paymentTestInstructionsContent': '1. 选择测试金额(建议使用0.01元进行测试)\n'
'2. 点击"发起微信支付"按钮\n'
'3. 系统将调用微信支付SDK\n'
'4. 在微信中完成支付流程\n'
'5. 返回应用查看支付结果\n\n'
'注意:这是测试环境,实际不会产生真实扣费',
'startingWechatPayment': '正在发起微信支付...',
'startingAlipayPayment': '正在发起支付宝支付...',
'wechatPaymentSuccess': '微信支付成功!',
'wechatPaymentFailed': '微信支付失败',
'wechatPaymentLaunchFailed': '微信支付启动失败',
'cannotLaunchWechatPayment': '无法启动微信支付',
'wechatPaymentException': '微信支付异常',
'wechatPaymentTestCompleted': '微信支付测试完成',
'alipayPaymentSuccess': '支付宝支付成功!',
'alipayPaymentFailed': '支付宝支付失败',
'alipayPaymentLaunchFailed': '支付宝支付启动失败',
'cannotLaunchAlipayPayment': '无法启动支付宝支付',
'alipayPaymentException': '支付宝支付异常',
// AI 功能卡片
'musicAndRecommendation': '听歌与推荐',
'navigationAndRoutes': '导航与路线',

59
lib/core/translations/language/zh_hk.dart

@ -232,6 +232,65 @@ const Map<String, String> zhHK = {
'totalQuota': '總額度',
'remaining': '剩餘',
'featureDescription': '功能說明',
'paymentSuccess': '付款成功',
'paymentFailed': '付款失敗',
'gotIt': '知道了',
'paymentFailedTryAgain': '付款失敗,請重試',
'selectPaymentMethod': '選擇付款方式',
'wechatPay': '微信支付',
'alipayPay': '支付寶',
'paypalPay': 'PayPal',
'appleIap': 'Apple 內購',
'googleIap': 'Google 內購',
'wechatOrderCreateFailed': '建立微信訂單失敗',
'alipayOrderCreateFailed': '建立支付寶訂單失敗',
'appleOrderCreateFailed': '建立 Apple 訂單失敗',
'googleOrderCreateFailed': '建立 Google 訂單失敗',
'paypalOrderCreateFailed': '建立 PayPal 訂單失敗',
'paymentException': '付款異常',
'paymentLaunchFailed': '付款啟動失敗',
'paymentExceptionWithError': '付款異常: @error',
'paymentProcessingCheckLater': '訂單處理中,請稍後查看。',
'paymentResultQueryException': '查詢付款結果異常: @error',
'orderConfirmedQuotaRefreshed': '訂單已確認,額度已更新',
'paymentCompletedConfirming': '付款完成,正在確認',
'paymentCancelled': '已取消付款',
'paypalOpenedCompleteInBrowser': '已開啟 PayPal,請在瀏覽器完成付款',
'paypalOpenFailed': '無法開啟 PayPal 付款頁面',
'paymentTestTitle': '付款測試',
'paymentTestOrderInfo': '測試訂單資訊',
'paymentTestProductId': '商品ID',
'paymentTestProductDescription': '商品描述',
'paymentTestWechatDescription': '微信支付測試',
'paymentTestAlipayDescription': '支付寶支付測試',
'paymentTestAmount': '付款金額',
'paymentTestSelectAmount': '選擇測試金額',
'paying': '付款中...',
'wechatPayWithAmount': '微信支付 ¥@amount',
'alipayPayWithAmount': '支付寶 ¥@amount',
'paymentStatusTitle': '付款狀態',
'errorInfoWithMessage': '錯誤資訊: @message',
'retest': '重新測試',
'paymentTestInstructionsTitle': '使用說明',
'paymentTestInstructionsContent': '1. 選擇測試金額(建議使用0.01元進行測試)\n'
'2. 點擊「微信支付」按鈕\n'
'3. 系統將呼叫微信支付 SDK\n'
'4. 在微信中完成付款流程\n'
'5. 返回應用查看付款結果\n\n'
'注意:這是測試環境,不會產生真實扣費',
'startingWechatPayment': '正在發起微信支付...',
'startingAlipayPayment': '正在發起支付寶支付...',
'wechatPaymentSuccess': '微信支付成功!',
'wechatPaymentFailed': '微信支付失敗',
'wechatPaymentLaunchFailed': '微信支付啟動失敗',
'cannotLaunchWechatPayment': '無法啟動微信支付',
'wechatPaymentException': '微信支付異常',
'wechatPaymentTestCompleted': '微信支付測試完成',
'alipayPaymentSuccess': '支付寶支付成功!',
'alipayPaymentFailed': '支付寶支付失敗',
'alipayPaymentLaunchFailed': '支付寶支付啟動失敗',
'cannotLaunchAlipayPayment': '無法啟動支付寶支付',
'alipayPaymentException': '支付寶支付異常',
// AI 功能卡片
'musicAndRecommendation': '聽歌與推薦',
'navigationAndRoutes': '導航與路線',

59
lib/core/translations/language/zh_tw.dart

@ -232,6 +232,65 @@ const Map<String, String> zhTW = {
'totalQuota': '總額度',
'remaining': '剩餘',
'featureDescription': '功能說明',
'paymentSuccess': '付款成功',
'paymentFailed': '付款失敗',
'gotIt': '知道了',
'paymentFailedTryAgain': '付款失敗,請重試',
'selectPaymentMethod': '選擇付款方式',
'wechatPay': '微信支付',
'alipayPay': '支付寶',
'paypalPay': 'PayPal',
'appleIap': 'Apple 內購',
'googleIap': 'Google 內購',
'wechatOrderCreateFailed': '建立微信訂單失敗',
'alipayOrderCreateFailed': '建立支付寶訂單失敗',
'appleOrderCreateFailed': '建立 Apple 訂單失敗',
'googleOrderCreateFailed': '建立 Google 訂單失敗',
'paypalOrderCreateFailed': '建立 PayPal 訂單失敗',
'paymentException': '付款異常',
'paymentLaunchFailed': '付款啟動失敗',
'paymentExceptionWithError': '付款異常: @error',
'paymentProcessingCheckLater': '訂單處理中,請稍後查看。',
'paymentResultQueryException': '查詢付款結果異常: @error',
'orderConfirmedQuotaRefreshed': '訂單已確認,額度已更新',
'paymentCompletedConfirming': '付款完成,正在確認',
'paymentCancelled': '已取消付款',
'paypalOpenedCompleteInBrowser': '已開啟 PayPal,請在瀏覽器完成付款',
'paypalOpenFailed': '無法開啟 PayPal 付款頁面',
'paymentTestTitle': '付款測試',
'paymentTestOrderInfo': '測試訂單資訊',
'paymentTestProductId': '商品ID',
'paymentTestProductDescription': '商品描述',
'paymentTestWechatDescription': '微信支付測試',
'paymentTestAlipayDescription': '支付寶支付測試',
'paymentTestAmount': '付款金額',
'paymentTestSelectAmount': '選擇測試金額',
'paying': '付款中...',
'wechatPayWithAmount': '微信支付 ¥@amount',
'alipayPayWithAmount': '支付寶 ¥@amount',
'paymentStatusTitle': '付款狀態',
'errorInfoWithMessage': '錯誤資訊: @message',
'retest': '重新測試',
'paymentTestInstructionsTitle': '使用說明',
'paymentTestInstructionsContent': '1. 選擇測試金額(建議使用0.01元進行測試)\n'
'2. 點擊「微信支付」按鈕\n'
'3. 系統將呼叫微信支付 SDK\n'
'4. 在微信中完成付款流程\n'
'5. 返回應用查看付款結果\n\n'
'注意:這是測試環境,不會產生真實扣費',
'startingWechatPayment': '正在發起微信支付...',
'startingAlipayPayment': '正在發起支付寶支付...',
'wechatPaymentSuccess': '微信支付成功!',
'wechatPaymentFailed': '微信支付失敗',
'wechatPaymentLaunchFailed': '微信支付啟動失敗',
'cannotLaunchWechatPayment': '無法啟動微信支付',
'wechatPaymentException': '微信支付異常',
'wechatPaymentTestCompleted': '微信支付測試完成',
'alipayPaymentSuccess': '支付寶支付成功!',
'alipayPaymentFailed': '支付寶支付失敗',
'alipayPaymentLaunchFailed': '支付寶支付啟動失敗',
'cannotLaunchAlipayPayment': '無法啟動支付寶支付',
'alipayPaymentException': '支付寶支付異常',
// AI 功能卡片
'musicAndRecommendation': '聽歌與推薦',
'navigationAndRoutes': '導航與路線',

92
lib/modules/goods/controllers/goods_base_controller.dart

@ -26,7 +26,7 @@ abstract class GoodsBaseController extends GetxController {
@override
void onInit() {
super.onInit();
_init();
_init(); // 初始化商品列表
// 处理冷启动场景:如果 App 通过深链直接启动
_handleInitialDeepLink();
}
@ -42,10 +42,10 @@ abstract class GoodsBaseController extends GetxController {
Future<void> _init() async {
loading.value = true;
error.value = '';
error.value = ''; // 重置错误信息
try {
final list = await fetchProducts();
items.assignAll(list);
final list = await fetchProducts(); // 获取商品列表
items.assignAll(list); // 更新商品列表
// iOS 环境下,在页面加载后批量查询当前商品的 IAP 详情,便于排查 StoreKit 可用商品
await _debugQueryIapProductsIfIos();
} catch (e) {
@ -84,21 +84,22 @@ abstract class GoodsBaseController extends GetxController {
/// 统一入口:根据后端配置决定是否弹出支付方式选择面板
Future<void> purchase(DBGoods item) async {
// 读取渠道配置
// 1. 获取可用的支付方式
final enabled = _getEnabledPayMethods();
// 无配置或多个渠道:弹出选择面板
// 2. 无配置或多个渠道:弹出选择面板
_PayMethod? method;
if (enabled.length != 1) {
method = await _showPayMethodSheet(enabled);
if (method == null) return;
} else {
// 仅一个渠道:直接走对应支付
// 3. 仅一个渠道:直接走对应支付
method = enabled.first;
}
// 4. 根据选择的支付方式执行支付
bool ok = false;
String failMsg = '支付失败,请重试';
String failMsg = 'paymentFailedTryAgain'.tr; // 支付失败,请重试
isPaying.value = true;
_startPayingTimeout();
if (method == _PayMethod.wechat) {
@ -122,9 +123,9 @@ abstract class GoodsBaseController extends GetxController {
if (!success) failMsg = msg ?? failMsg;
});
}
// 5. 处理失败结果
if (!ok) {
Get.snackbar('提示', failMsg,
Get.snackbar('tip'.tr, failMsg,
snackPosition: SnackPosition.BOTTOM,
margin: const EdgeInsets.all(12));
}
@ -133,8 +134,10 @@ abstract class GoodsBaseController extends GetxController {
/// 解析后端 paychannels 并结合平台过滤可用支付方式
List<_PayMethod> _getEnabledPayMethods() {
try {
//1. 获取后端配置的支付渠道
final paychannels =
VersionUpdateService.to.cachedAppInfo?.paychannels ?? '';
print('[Pay] 后端配置的支付渠道: $paychannels');
final raw = paychannels
.split(',')
.map((e) => e.trim().toLowerCase())
@ -230,7 +233,7 @@ abstract class GoodsBaseController extends GetxController {
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
'选择支付方式',
'selectPaymentMethod'.tr, // 选择支付方式
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
@ -266,7 +269,7 @@ abstract class GoodsBaseController extends GetxController {
),
const SizedBox(height: 8),
Text(
'微信支付',
'wechatPay'.tr, // 微信支付
style: TextStyle(
fontSize: 13,
color: isDark ? Colors.white : Colors.black,
@ -300,7 +303,7 @@ abstract class GoodsBaseController extends GetxController {
),
const SizedBox(height: 8),
Text(
'支付宝',
'alipayPay'.tr, // 支付宝
style: TextStyle(
fontSize: 13,
color: isDark ? Colors.white : Colors.black,
@ -336,7 +339,7 @@ abstract class GoodsBaseController extends GetxController {
),
const SizedBox(height: 8),
Text(
'PayPal',
'paypalPay'.tr, // PayPal
style: TextStyle(
fontSize: 13,
color: isDark ? Colors.white : Colors.black,
@ -372,7 +375,7 @@ abstract class GoodsBaseController extends GetxController {
),
const SizedBox(height: 8),
Text(
'Apple 内购',
'appleIap'.tr, // Apple 内购
style: TextStyle(
fontSize: 13,
color: isDark ? Colors.white : Colors.black,
@ -408,7 +411,7 @@ abstract class GoodsBaseController extends GetxController {
),
const SizedBox(height: 8),
Text(
'Google 内购',
'googleIap'.tr, // Google 内购
style: TextStyle(
fontSize: 13,
color: isDark ? Colors.white : Colors.black,
@ -445,7 +448,7 @@ abstract class GoodsBaseController extends GetxController {
notifyUrl: '$serverUrl/api/home/pay_wechatnotify',
);
if (paymentData == null) {
onResult?.call(false, '创建微信订单失败');
onResult?.call(false, 'wechatOrderCreateFailed'.tr); // 创建微信订单失败
isPaying.value = false;
_cancelPayingTimeout();
return false;
@ -465,7 +468,7 @@ abstract class GoodsBaseController extends GetxController {
} else {
isPaying.value = false;
_cancelPayingTimeout();
_showPayResultDialog(false, msg ?? '支付失败');
_showPayResultDialog(false, msg ?? 'paymentFailed'.tr); // 支付失败
}
},
);
@ -482,7 +485,7 @@ abstract class GoodsBaseController extends GetxController {
notifyUrl: 'https://api.ideapsound.com/api/home/pay_alipaynotify',
);
if (orderInfo == null) {
onResult?.call(false, '创建支付宝订单失败');
onResult?.call(false, 'alipayOrderCreateFailed'.tr); // 创建支付宝订单失败
isPaying.value = false;
_cancelPayingTimeout();
return false;
@ -500,7 +503,7 @@ abstract class GoodsBaseController extends GetxController {
} else {
isPaying.value = false;
_cancelPayingTimeout();
_showPayResultDialog(false, msg ?? '支付失败');
_showPayResultDialog(false, msg ?? 'paymentFailed'.tr); // 支付失败
}
},
);
@ -517,7 +520,7 @@ abstract class GoodsBaseController extends GetxController {
amount: item.price,
);
if (orderId == null || orderId.isEmpty) {
onResult?.call(false, '创建 Apple 订单失败');
onResult?.call(false, 'appleOrderCreateFailed'.tr); // 创建 Apple 订单失败
isPaying.value = false;
_cancelPayingTimeout();
return false;
@ -547,7 +550,7 @@ abstract class GoodsBaseController extends GetxController {
isPaying.value = false;
_cancelPayingTimeout();
} else {
Get.snackbar('提示', msg,
Get.snackbar('tip'.tr, msg,
snackPosition: SnackPosition.BOTTOM,
margin: const EdgeInsets.all(12));
}
@ -555,7 +558,10 @@ abstract class GoodsBaseController extends GetxController {
},
);
} catch (e) {
onResult?.call(false, 'Apple 内购异常: $e');
onResult?.call(
false,
'paymentExceptionWithError'
.trParams({'error': e.toString()})); // 支付异常: @error
isPaying.value = false;
_cancelPayingTimeout();
return false;
@ -573,7 +579,7 @@ abstract class GoodsBaseController extends GetxController {
amount: item.price,
);
if (orderId == null || orderId.isEmpty) {
onResult?.call(false, '创建 Google 订单失败');
onResult?.call(false, 'googleOrderCreateFailed'.tr); // 创建 Google 订单失败
isPaying.value = false;
_cancelPayingTimeout();
return false;
@ -602,7 +608,7 @@ abstract class GoodsBaseController extends GetxController {
isPaying.value = false;
_cancelPayingTimeout();
} else {
Get.snackbar('提示', msg,
Get.snackbar('tip'.tr, msg,
snackPosition: SnackPosition.BOTTOM,
margin: const EdgeInsets.all(12));
}
@ -610,7 +616,10 @@ abstract class GoodsBaseController extends GetxController {
},
);
} catch (e) {
onResult?.call(false, 'Google 内购异常: $e');
onResult?.call(
false,
'paymentExceptionWithError'
.trParams({'error': e.toString()})); // 支付异常: @error
isPaying.value = false;
_cancelPayingTimeout();
return false;
@ -641,11 +650,12 @@ abstract class GoodsBaseController extends GetxController {
}) async {
// 若无法获取订单号,直接弹成功提示但提醒稍后刷新
if (orderId == null || orderId.isEmpty) {
_showPayResultDialog(true, '${channel}支付成功,订单处理中,请稍后查看。');
_showPayResultDialog(
true, 'paymentProcessingCheckLater'.tr); // 订单处理中,请稍后查看
return;
}
String message = initialMessage ?? '${channel}支付成功';
String message = initialMessage ?? 'paymentSuccess'.tr; // 支付成功
bool success = false;
try {
// 简单轮询回查,避免回调延迟
@ -677,7 +687,8 @@ abstract class GoodsBaseController extends GetxController {
} catch (_) {}
}
} catch (e) {
message = '查询支付结果异常: $e';
message = 'paymentResultQueryException'
.trParams({'error': e.toString()}); // 查询支付结果异常: @error
}
_showPayResultDialog(success, message);
}
@ -695,7 +706,7 @@ abstract class GoodsBaseController extends GetxController {
if (orderStatus == 1 && user != null) {
User.instance.updateUserInfo(user);
_payService.setVipExptime(User.instance.vipexptime);
Get.snackbar('提示', '订单已确认,额度已刷新',
Get.snackbar('tip'.tr, 'orderConfirmedQuotaRefreshed'.tr,
snackPosition: SnackPosition.BOTTOM,
margin: const EdgeInsets.all(12));
return;
@ -718,6 +729,8 @@ abstract class GoodsBaseController extends GetxController {
final context = Get.context;
final isDark =
context != null && Theme.of(context).brightness == Brightness.dark;
final titleText =
success ? 'paymentSuccess'.tr : 'paymentFailed'.tr; // 支付成功/支付失败
Get.dialog(
Dialog(
insetPadding: const EdgeInsets.symmetric(horizontal: 24, vertical: 24),
@ -753,7 +766,7 @@ abstract class GoodsBaseController extends GetxController {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
success ? '支付成功' : '支付失败',
titleText,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w700,
@ -781,7 +794,7 @@ abstract class GoodsBaseController extends GetxController {
children: [
TextButton(
onPressed: () => Get.back(),
child: const Text('知道了'),
child: Text('gotIt'.tr), // 知道了
),
],
),
@ -817,7 +830,7 @@ abstract class GoodsBaseController extends GetxController {
notifyUrl: 'https://api.ideapsound.com/api/home/pay_paypalnotify',
);
if (approvalUrl == null) {
onResult?.call(false, '创建 PayPal 订单失败');
onResult?.call(false, 'paypalOrderCreateFailed'.tr); // 创建 PayPal 订单失败
isPaying.value = false;
_cancelPayingTimeout();
return false;
@ -846,14 +859,14 @@ abstract class GoodsBaseController extends GetxController {
await _confirmOrderAndShow(
orderId,
channel: 'PayPal',
initialMessage: '支付完成,正在确认',
initialMessage: 'paymentCompletedConfirming'.tr, // 支付完成,正在确认
retries: 1,
intervalMs: 0,
);
} else if (path == '/cancel') {
isPaying.value = false;
_cancelPayingTimeout();
_showPayResultDialog(false, '已取消支付');
_showPayResultDialog(false, 'paymentCancelled'.tr); // 已取消支付
}
// 一次性监听,处理后即取消
_deeplinkSub?.cancel();
@ -871,12 +884,13 @@ abstract class GoodsBaseController extends GetxController {
if (success) {
// 仅提示已打开授权页面,不在此处回查与弹窗,等待深链回跳后再处理
print('[PayPal] 已打开授权页面,等待回跳后再确认。orderId: $orderId');
Get.snackbar('提示', msg ?? '已打开 PayPal,请在浏览器完成支付',
Get.snackbar('tip'.tr, msg ?? 'paypalOpenedCompleteInBrowser'.tr,
snackPosition: SnackPosition.BOTTOM,
margin: const EdgeInsets.all(12));
} else {
// 无法打开授权页才提示失败
_showPayResultDialog(false, msg ?? '无法打开 PayPal 支付页面');
_showPayResultDialog(
false, msg ?? 'paypalOpenFailed'.tr); // 无法打开 PayPal 支付页面
}
},
);
@ -899,13 +913,13 @@ abstract class GoodsBaseController extends GetxController {
await _confirmOrderAndShow(
orderId,
channel: 'PayPal',
initialMessage: '支付完成,正在确认',
initialMessage: 'paymentCompletedConfirming'.tr, // 支付完成,正在确认
retries: 1,
intervalMs: 0,
);
}
} else if (uri.path == '/cancel') {
_showPayResultDialog(false, '已取消支付');
_showPayResultDialog(false, 'paymentCancelled'.tr); // 已取消支付
}
}
} catch (_) {

48
lib/modules/payment/controllers/payment_controller.dart

@ -27,32 +27,32 @@ class PaymentController extends GetxController {
Future<void> testWechatPayment() async {
try {
isLoading.value = true;
paymentStatus.value = '正在发起微信支付...';
paymentStatus.value = 'startingWechatPayment'.tr; // 正在发起微信支付...
errorMessage.value = '';
// 调用支付服务,使用回调处理结果
final launched = await _payService.processWechatPayment(
productId: testProductId.value,
amount: (testAmount.value * 100).toInt(), // 转换为分
description: '微信支付测试',
description: 'paymentTestWechatDescription'.tr, // 微信支付测试
onResult: (success, message) {
// 支付结果回调
isLoading.value = false;
if (success) {
paymentStatus.value = '微信支付成功!';
paymentStatus.value = 'wechatPaymentSuccess'.tr; // 微信支付成功!
errorMessage.value = '';
Get.snackbar(
'支付成功',
message ?? '微信支付测试完成',
'paymentSuccess'.tr, // 支付成功
message ?? 'wechatPaymentTestCompleted'.tr, // 微信支付测试完成
snackPosition: SnackPosition.TOP,
);
} else {
paymentStatus.value = '微信支付失败';
errorMessage.value = message ?? '未知错误';
paymentStatus.value = 'wechatPaymentFailed'.tr; // 微信支付失败
errorMessage.value = message ?? 'unknownError'.tr; // 未知错误
Get.snackbar(
'支付失败',
message ?? '未知错误',
'paymentFailed'.tr, // 支付失败
message ?? 'unknownError'.tr, // 未知错误
snackPosition: SnackPosition.TOP,
);
}
@ -62,15 +62,15 @@ class PaymentController extends GetxController {
if (!launched) {
// 如果支付没有成功启动
isLoading.value = false;
paymentStatus.value = '微信支付启动失败';
errorMessage.value = '无法启动微信支付';
Get.snackbar('支付启动失败', '无法启动微信支付');
paymentStatus.value = 'wechatPaymentLaunchFailed'.tr; // 微信支付启动失败
errorMessage.value = 'cannotLaunchWechatPayment'.tr; // 无法启动微信支付
Get.snackbar('paymentLaunchFailed'.tr, 'cannotLaunchWechatPayment'.tr);
}
} catch (e) {
isLoading.value = false;
paymentStatus.value = '微信支付异常';
paymentStatus.value = 'wechatPaymentException'.tr; // 微信支付异常
errorMessage.value = e.toString();
Get.snackbar('支付异常', e.toString());
Get.snackbar('paymentException'.tr, e.toString()); // 支付异常
}
}
@ -78,24 +78,24 @@ class PaymentController extends GetxController {
Future<void> testAlipayPayment() async {
try {
isLoading.value = true;
paymentStatus.value = '正在发起支付宝支付...';
paymentStatus.value = 'startingAlipayPayment'.tr; // 正在发起支付宝支付...
errorMessage.value = '';
// 调用支付宝支付服务
final launched = await _payService.processAlipayPayment(
productId: testProductId.value, // 这里传递的是产品ID
amount: (testAmount.value * 100).toInt(), // 转换为分
description: '支付宝支付测试',
description: 'paymentTestAlipayDescription'.tr, // 支付宝支付测试
onResult: (success, message) {
// 支付结果回调
isLoading.value = false;
if (success) {
paymentStatus.value = '支付宝支付成功!';
paymentStatus.value = 'alipayPaymentSuccess'.tr; // 支付宝支付成功!
errorMessage.value = '';
} else {
paymentStatus.value = '支付宝支付失败';
errorMessage.value = message;
paymentStatus.value = 'alipayPaymentFailed'.tr; // 支付宝支付失败
errorMessage.value = message ?? 'unknownError'.tr; // 未知错误
}
},
);
@ -103,15 +103,15 @@ class PaymentController extends GetxController {
if (!launched) {
// 如果支付没有成功启动
isLoading.value = false;
paymentStatus.value = '支付宝支付启动失败';
errorMessage.value = '无法启动支付宝支付';
Get.snackbar('支付启动失败', '无法启动支付宝支付');
paymentStatus.value = 'alipayPaymentLaunchFailed'.tr; // 支付宝支付启动失败
errorMessage.value = 'cannotLaunchAlipayPayment'.tr; // 无法启动支付宝支付
Get.snackbar('paymentLaunchFailed'.tr, 'cannotLaunchAlipayPayment'.tr);
}
} catch (e) {
isLoading.value = false;
paymentStatus.value = '支付宝支付异常';
paymentStatus.value = 'alipayPaymentException'.tr; // 支付宝支付异常
errorMessage.value = e.toString();
Get.snackbar('支付异常', e.toString());
Get.snackbar('paymentException'.tr, e.toString()); // 支付异常
}
}

55
lib/modules/payment/views/payment_view.dart

@ -16,7 +16,7 @@ class PaymentView extends GetView<PaymentController> {
backgroundColor: isDarkMode ? Colors.black : Colors.white,
elevation: 0.5,
title: Text(
'支付测试',
'paymentTestTitle'.tr, // 支付测试
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.w600,
@ -76,7 +76,7 @@ class PaymentView extends GetView<PaymentController> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'测试订单信息',
'paymentTestOrderInfo'.tr, // 测试订单信息
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
@ -85,12 +85,17 @@ class PaymentView extends GetView<PaymentController> {
),
SizedBox(height: 12.h),
Obx(() => _buildInfoRow(
'商品ID', controller.testProductId.value, isDarkMode)),
'paymentTestProductId'.tr, // 商品ID
controller.testProductId.value,
isDarkMode)),
SizedBox(height: 8.h),
_buildInfoRow('商品描述', '微信支付测试', isDarkMode),
_buildInfoRow(
'paymentTestProductDescription'.tr, // 商品描述
'paymentTestWechatDescription'.tr, // 微信支付测试
isDarkMode),
SizedBox(height: 8.h),
Obx(() => _buildInfoRow(
'支付金额',
'paymentTestAmount'.tr, // 支付金额
'¥${controller.testAmount.value.toStringAsFixed(2)}',
isDarkMode)),
],
@ -147,7 +152,7 @@ class PaymentView extends GetView<PaymentController> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'选择测试金额',
'paymentTestSelectAmount'.tr, // 选择测试金额
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
@ -209,7 +214,7 @@ class PaymentView extends GetView<PaymentController> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'选择支付方式',
'selectPaymentMethod'.tr, // 选择支付方式
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
@ -222,7 +227,7 @@ class PaymentView extends GetView<PaymentController> {
children: [
_buildPaymentMethodOption(
method: 1,
title: '微信支付',
title: 'wechatPay'.tr, // 微信支付
icon: Icons.wechat,
iconColor: Colors.green,
isDarkMode: isDarkMode,
@ -230,7 +235,7 @@ class PaymentView extends GetView<PaymentController> {
SizedBox(height: 12.h),
_buildPaymentMethodOption(
method: 2,
title: '支付宝支付',
title: 'alipayPay'.tr, // 支付宝支付
icon: Icons.account_balance_wallet,
iconColor: Colors.blue,
isDarkMode: isDarkMode,
@ -320,7 +325,7 @@ class PaymentView extends GetView<PaymentController> {
),
elevation: 2,
),
child: controller.isLoading.value
child: controller.isLoading.value
? Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
@ -335,7 +340,7 @@ class PaymentView extends GetView<PaymentController> {
),
SizedBox(width: 12.w),
Text(
'支付中...',
'paying'.tr, // 支付中...
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
@ -357,8 +362,16 @@ class PaymentView extends GetView<PaymentController> {
SizedBox(width: 8.w),
Text(
controller.selectedPaymentMethod.value == 1
? '微信支付 ¥${controller.testAmount.value.toStringAsFixed(2)}'
: '支付宝支付 ¥${controller.testAmount.value.toStringAsFixed(2)}',
? 'wechatPayWithAmount'.trParams({
'amount':
controller.testAmount.value.toStringAsFixed(
2)
}) // 微信支付 ¥@amount
: 'alipayPayWithAmount'.trParams({
'amount':
controller.testAmount.value.toStringAsFixed(
2)
}), // 支付宝支付 ¥@amount
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
@ -404,7 +417,7 @@ class PaymentView extends GetView<PaymentController> {
),
SizedBox(width: 8.w),
Text(
'支付状态',
'paymentStatusTitle'.tr, // 支付状态
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
@ -424,7 +437,8 @@ class PaymentView extends GetView<PaymentController> {
if (controller.errorMessage.value.isNotEmpty) ...[
SizedBox(height: 8.h),
Text(
'错误信息: ${controller.errorMessage.value}',
'errorInfoWithMessage'.trParams(
{'message': controller.errorMessage.value}), // 错误信息: @message
style: TextStyle(
fontSize: 12.sp,
color: Colors.red[600],
@ -442,7 +456,7 @@ class PaymentView extends GetView<PaymentController> {
),
),
child: Text(
'重新测试',
'retest'.tr, // 重新测试
style: TextStyle(
color: isError ? Colors.red[600] : Colors.green[600],
),
@ -479,7 +493,7 @@ class PaymentView extends GetView<PaymentController> {
),
SizedBox(width: 8.w),
Text(
'使用说明',
'paymentTestInstructionsTitle'.tr, // 使用说明
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
@ -490,12 +504,7 @@ class PaymentView extends GetView<PaymentController> {
),
SizedBox(height: 12.h),
Text(
'1. 选择测试金额(建议使用0.01元进行测试)\n'
'2. 点击"发起微信支付"按钮\n'
'3. 系统将调用微信支付SDK\n'
'4. 在微信中完成支付流程\n'
'5. 返回应用查看支付结果\n\n'
'注意:这是测试环境,实际不会产生真实扣费',
'paymentTestInstructionsContent'.tr, // 1. 选择测试金额(建议使用0.01元进行测试)...
style: TextStyle(
fontSize: 14.sp,
color: isDarkMode ? Colors.grey[300] : Colors.grey[700],

Loading…
Cancel
Save