7 changed files with 669 additions and 0 deletions
@ -0,0 +1,175 @@ |
|||||
|
import 'package:get/get.dart'; |
||||
|
import 'package:fluwx/fluwx.dart'; |
||||
|
import '../../modules/login/controllers/weixinLogin.dart'; |
||||
|
|
||||
|
/// 支付结果回调 |
||||
|
typedef PaymentResultCallback = void Function(bool success, String? message); |
||||
|
|
||||
|
/// 支付服务 |
||||
|
class PayService extends GetxService { |
||||
|
late FlWX _flwx; |
||||
|
|
||||
|
@override |
||||
|
void onInit() { |
||||
|
super.onInit(); |
||||
|
_flwx = FlWX(); |
||||
|
} |
||||
|
|
||||
|
/// 微信支付 |
||||
|
/// |
||||
|
/// [paymentData] 支付参数,包含以下字段: |
||||
|
/// - appId: 应用ID |
||||
|
/// - partnerId: 商户号 |
||||
|
/// - prepayId: 预支付交易会话ID |
||||
|
/// - packageValue: 扩展字段,固定值"Sign=WXPay" |
||||
|
/// - nonceStr: 随机字符串 |
||||
|
/// - timestamp: 时间戳 |
||||
|
/// - sign: 签名 |
||||
|
/// |
||||
|
/// [onResult] 支付结果回调 |
||||
|
Future<bool> wechatPay({ |
||||
|
required Map<String, dynamic> paymentData, |
||||
|
PaymentResultCallback? onResult, |
||||
|
}) async { |
||||
|
try { |
||||
|
// 检查微信是否安装 |
||||
|
if (!await _flwx.isInstalled) { |
||||
|
onResult?.call(false, '微信未安装'); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// 将支付数据转换为Payment对象 |
||||
|
final payment = paymentData.toPayment(); |
||||
|
if (payment == null) { |
||||
|
onResult?.call(false, '支付参数格式错误'); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// 调用微信支付 |
||||
|
final result = await _flwx.pay( |
||||
|
payment, |
||||
|
onSuccess: () { |
||||
|
onResult?.call(true, '支付成功'); |
||||
|
}, |
||||
|
onResponse: (response) { |
||||
|
if (response.errCode == 0) { |
||||
|
onResult?.call(true, '支付成功'); |
||||
|
} else if (response.errCode == -2) { |
||||
|
onResult?.call(false, '用户取消支付'); |
||||
|
} else { |
||||
|
onResult?.call(false, '支付失败: ${response.errStr}'); |
||||
|
} |
||||
|
}, |
||||
|
); |
||||
|
|
||||
|
return result; |
||||
|
} catch (e) { |
||||
|
onResult?.call(false, '支付异常: $e'); |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// 创建微信支付订单 |
||||
|
/// |
||||
|
/// [orderInfo] 订单信息,包含: |
||||
|
/// - orderId: 订单ID |
||||
|
/// - amount: 支付金额(分) |
||||
|
/// - description: 商品描述 |
||||
|
/// - userId: 用户ID |
||||
|
/// |
||||
|
/// 返回支付参数,用于调用 [wechatPay] 方法 |
||||
|
Future<Map<String, dynamic>?> createWechatPayOrder({ |
||||
|
required String orderId, |
||||
|
required int amount, |
||||
|
required String description, |
||||
|
String? userId, |
||||
|
}) async { |
||||
|
try { |
||||
|
// TODO: 这里需要调用后端API创建支付订单 |
||||
|
// 示例代码,实际需要根据后端接口调整 |
||||
|
|
||||
|
// final response = await Api.createPayOrder({ |
||||
|
// 'orderId': orderId, |
||||
|
// 'amount': amount, |
||||
|
// 'description': description, |
||||
|
// 'userId': userId, |
||||
|
// 'payType': 'wechat', |
||||
|
// }); |
||||
|
|
||||
|
// if (response['success'] == true) { |
||||
|
// return response['data'] as Map<String, dynamic>; |
||||
|
// } |
||||
|
|
||||
|
// 临时返回示例数据结构,实际使用时需要删除 |
||||
|
return { |
||||
|
'appId': 'your_app_id', |
||||
|
'partnerId': 'your_partner_id', |
||||
|
'prepayId': 'prepay_id_from_server', |
||||
|
'packageValue': 'Sign=WXPay', |
||||
|
'nonceStr': 'random_string', |
||||
|
'timestamp': DateTime.now().millisecondsSinceEpoch ~/ 1000, |
||||
|
'sign': 'signature_from_server', |
||||
|
}; |
||||
|
} catch (e) { |
||||
|
print('创建支付订单失败: $e'); |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// 查询支付结果 |
||||
|
/// |
||||
|
/// [orderId] 订单ID |
||||
|
/// 返回支付状态:success, failed, pending |
||||
|
Future<String?> queryPaymentStatus(String orderId) async { |
||||
|
try { |
||||
|
// TODO: 调用后端API查询支付状态 |
||||
|
// final response = await Api.queryPaymentStatus({'orderId': orderId}); |
||||
|
// return response['status'] as String?; |
||||
|
|
||||
|
// 临时返回,实际使用时需要删除 |
||||
|
return 'pending'; |
||||
|
} catch (e) { |
||||
|
print('查询支付状态失败: $e'); |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// 完整的支付流程 |
||||
|
/// |
||||
|
/// [orderId] 订单ID |
||||
|
/// [amount] 支付金额(分) |
||||
|
/// [description] 商品描述 |
||||
|
/// [userId] 用户ID |
||||
|
/// [onResult] 支付结果回调 |
||||
|
Future<bool> processWechatPayment({ |
||||
|
required String orderId, |
||||
|
required int amount, |
||||
|
required String description, |
||||
|
String? userId, |
||||
|
PaymentResultCallback? onResult, |
||||
|
}) async { |
||||
|
try { |
||||
|
// 1. 创建支付订单 |
||||
|
final paymentData = await createWechatPayOrder( |
||||
|
orderId: orderId, |
||||
|
amount: amount, |
||||
|
description: description, |
||||
|
userId: userId, |
||||
|
); |
||||
|
|
||||
|
if (paymentData == null) { |
||||
|
onResult?.call(false, '创建支付订单失败'); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// 2. 调用微信支付 |
||||
|
return await wechatPay( |
||||
|
paymentData: paymentData, |
||||
|
onResult: onResult, |
||||
|
); |
||||
|
} catch (e) { |
||||
|
onResult?.call(false, '支付流程异常: $e'); |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
import 'package:get/get.dart'; |
||||
|
import '../controllers/payment_controller.dart'; |
||||
|
|
||||
|
class PaymentBinding extends Bindings { |
||||
|
@override |
||||
|
void dependencies() { |
||||
|
Get.lazyPut<PaymentController>(() => PaymentController()); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,85 @@ |
|||||
|
import 'package:get/get.dart'; |
||||
|
import '../../../data/services/pay_service.dart'; |
||||
|
|
||||
|
class PaymentController extends GetxController { |
||||
|
final PayService _payService = Get.find<PayService>(); |
||||
|
|
||||
|
// 支付状态 |
||||
|
final RxBool isLoading = false.obs; |
||||
|
final RxString paymentStatus = ''.obs; |
||||
|
final RxString errorMessage = ''.obs; |
||||
|
|
||||
|
// 测试订单信息 |
||||
|
final RxString testOrderId = ''.obs; |
||||
|
final RxDouble testAmount = 0.01.obs; // 测试金额 1分钱 |
||||
|
|
||||
|
@override |
||||
|
void onInit() { |
||||
|
super.onInit(); |
||||
|
// 生成测试订单ID |
||||
|
testOrderId.value = 'test_${DateTime.now().millisecondsSinceEpoch}'; |
||||
|
} |
||||
|
|
||||
|
/// 测试微信支付 |
||||
|
Future<void> testWechatPayment() async { |
||||
|
try { |
||||
|
isLoading.value = true; |
||||
|
paymentStatus.value = '正在发起支付...'; |
||||
|
errorMessage.value = ''; |
||||
|
|
||||
|
// 调用支付服务,使用回调处理结果 |
||||
|
final launched = await _payService.processWechatPayment( |
||||
|
orderId: testOrderId.value, |
||||
|
amount: (testAmount.value * 100).toInt(), // 转换为分 |
||||
|
description: '微信支付测试', |
||||
|
onResult: (success, message) { |
||||
|
// 支付结果回调 |
||||
|
isLoading.value = false; |
||||
|
|
||||
|
if (success) { |
||||
|
paymentStatus.value = '支付成功!'; |
||||
|
errorMessage.value = ''; |
||||
|
Get.snackbar( |
||||
|
'支付成功', |
||||
|
message ?? '微信支付测试完成', |
||||
|
snackPosition: SnackPosition.TOP, |
||||
|
); |
||||
|
} else { |
||||
|
paymentStatus.value = '支付失败'; |
||||
|
errorMessage.value = message ?? '未知错误'; |
||||
|
Get.snackbar( |
||||
|
'支付失败', |
||||
|
message ?? '未知错误', |
||||
|
snackPosition: SnackPosition.TOP, |
||||
|
); |
||||
|
} |
||||
|
}, |
||||
|
); |
||||
|
|
||||
|
if (!launched) { |
||||
|
// 如果支付没有成功启动 |
||||
|
isLoading.value = false; |
||||
|
paymentStatus.value = '支付启动失败'; |
||||
|
errorMessage.value = '无法启动微信支付'; |
||||
|
Get.snackbar('支付启动失败', '无法启动微信支付'); |
||||
|
} |
||||
|
} catch (e) { |
||||
|
isLoading.value = false; |
||||
|
paymentStatus.value = '支付异常'; |
||||
|
errorMessage.value = e.toString(); |
||||
|
Get.snackbar('支付异常', e.toString()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// 重置状态 |
||||
|
void resetStatus() { |
||||
|
paymentStatus.value = ''; |
||||
|
errorMessage.value = ''; |
||||
|
testOrderId.value = 'test_${DateTime.now().millisecondsSinceEpoch}'; |
||||
|
} |
||||
|
|
||||
|
/// 更新测试金额 |
||||
|
void updateTestAmount(double amount) { |
||||
|
testAmount.value = amount; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,365 @@ |
|||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:get/get.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
import '../controllers/payment_controller.dart'; |
||||
|
|
||||
|
class PaymentView extends GetView<PaymentController> { |
||||
|
const PaymentView({Key? key}) : super(key: key); |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
final isDarkMode = Theme.of(context).brightness == Brightness.dark; |
||||
|
|
||||
|
return Scaffold( |
||||
|
backgroundColor: isDarkMode ? Colors.black : Colors.grey[50], |
||||
|
appBar: AppBar( |
||||
|
backgroundColor: isDarkMode ? Colors.black : Colors.white, |
||||
|
elevation: 0.5, |
||||
|
title: Text( |
||||
|
'微信支付测试', |
||||
|
style: TextStyle( |
||||
|
fontSize: 18.sp, |
||||
|
fontWeight: FontWeight.w600, |
||||
|
color: isDarkMode ? Colors.white : Colors.black, |
||||
|
), |
||||
|
), |
||||
|
centerTitle: true, |
||||
|
leading: IconButton( |
||||
|
icon: Icon( |
||||
|
Icons.arrow_back_ios, |
||||
|
color: isDarkMode ? Colors.white : Colors.black, |
||||
|
), |
||||
|
onPressed: () => Get.back(), |
||||
|
), |
||||
|
), |
||||
|
body: SingleChildScrollView( |
||||
|
padding: EdgeInsets.all(16.w), |
||||
|
child: Column( |
||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||
|
children: [ |
||||
|
_buildTestInfoCard(isDarkMode), |
||||
|
SizedBox(height: 20.h), |
||||
|
_buildAmountSelector(isDarkMode), |
||||
|
SizedBox(height: 20.h), |
||||
|
_buildPaymentButton(isDarkMode), |
||||
|
SizedBox(height: 20.h), |
||||
|
_buildStatusCard(isDarkMode), |
||||
|
SizedBox(height: 20.h), |
||||
|
_buildInstructions(isDarkMode), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
/// 测试信息卡片 |
||||
|
Widget _buildTestInfoCard(bool isDarkMode) { |
||||
|
return Container( |
||||
|
padding: EdgeInsets.all(16.w), |
||||
|
decoration: BoxDecoration( |
||||
|
color: isDarkMode ? Colors.grey[900] : Colors.white, |
||||
|
borderRadius: BorderRadius.circular(12.r), |
||||
|
boxShadow: [ |
||||
|
BoxShadow( |
||||
|
color: Colors.black.withOpacity(0.05), |
||||
|
blurRadius: 10, |
||||
|
offset: const Offset(0, 2), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
child: Column( |
||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||
|
children: [ |
||||
|
Text( |
||||
|
'测试订单信息', |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.sp, |
||||
|
fontWeight: FontWeight.w600, |
||||
|
color: isDarkMode ? Colors.white : Colors.black, |
||||
|
), |
||||
|
), |
||||
|
SizedBox(height: 12.h), |
||||
|
Obx(() => _buildInfoRow('订单ID', controller.testOrderId.value, isDarkMode)), |
||||
|
SizedBox(height: 8.h), |
||||
|
_buildInfoRow('商品描述', '微信支付测试', isDarkMode), |
||||
|
SizedBox(height: 8.h), |
||||
|
Obx(() => _buildInfoRow('支付金额', '¥${controller.testAmount.value.toStringAsFixed(2)}', isDarkMode)), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
/// 信息行 |
||||
|
Widget _buildInfoRow(String label, String value, bool isDarkMode) { |
||||
|
return Row( |
||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||
|
children: [ |
||||
|
SizedBox( |
||||
|
width: 80.w, |
||||
|
child: Text( |
||||
|
'$label:', |
||||
|
style: TextStyle( |
||||
|
fontSize: 14.sp, |
||||
|
color: isDarkMode ? Colors.grey[400] : Colors.grey[600], |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
Expanded( |
||||
|
child: Text( |
||||
|
value, |
||||
|
style: TextStyle( |
||||
|
fontSize: 14.sp, |
||||
|
color: isDarkMode ? Colors.white : Colors.black, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
/// 金额选择器 |
||||
|
Widget _buildAmountSelector(bool isDarkMode) { |
||||
|
final amounts = [0.01, 0.10, 1.00, 10.00]; |
||||
|
|
||||
|
return Container( |
||||
|
padding: EdgeInsets.all(16.w), |
||||
|
decoration: BoxDecoration( |
||||
|
color: isDarkMode ? Colors.grey[900] : Colors.white, |
||||
|
borderRadius: BorderRadius.circular(12.r), |
||||
|
boxShadow: [ |
||||
|
BoxShadow( |
||||
|
color: Colors.black.withOpacity(0.05), |
||||
|
blurRadius: 10, |
||||
|
offset: const Offset(0, 2), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
child: Column( |
||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||
|
children: [ |
||||
|
Text( |
||||
|
'选择测试金额', |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.sp, |
||||
|
fontWeight: FontWeight.w600, |
||||
|
color: isDarkMode ? Colors.white : Colors.black, |
||||
|
), |
||||
|
), |
||||
|
SizedBox(height: 12.h), |
||||
|
Wrap( |
||||
|
spacing: 12.w, |
||||
|
runSpacing: 8.h, |
||||
|
children: amounts.map((amount) { |
||||
|
return Obx(() => GestureDetector( |
||||
|
onTap: () => controller.updateTestAmount(amount), |
||||
|
child: Container( |
||||
|
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h), |
||||
|
decoration: BoxDecoration( |
||||
|
color: controller.testAmount.value == amount |
||||
|
? Colors.blue[600] |
||||
|
: (isDarkMode ? Colors.grey[800] : Colors.grey[200]), |
||||
|
borderRadius: BorderRadius.circular(20.r), |
||||
|
), |
||||
|
child: Text( |
||||
|
'¥${amount.toStringAsFixed(2)}', |
||||
|
style: TextStyle( |
||||
|
fontSize: 14.sp, |
||||
|
color: controller.testAmount.value == amount |
||||
|
? Colors.white |
||||
|
: (isDarkMode ? Colors.white : Colors.black), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
)); |
||||
|
}).toList(), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
/// 支付按钮 |
||||
|
Widget _buildPaymentButton(bool isDarkMode) { |
||||
|
return Obx(() => SizedBox( |
||||
|
width: double.infinity, |
||||
|
height: 50.h, |
||||
|
child: ElevatedButton( |
||||
|
onPressed: controller.isLoading.value ? null : controller.testWechatPayment, |
||||
|
style: ElevatedButton.styleFrom( |
||||
|
backgroundColor: Colors.green[600], |
||||
|
foregroundColor: Colors.white, |
||||
|
shape: RoundedRectangleBorder( |
||||
|
borderRadius: BorderRadius.circular(12.r), |
||||
|
), |
||||
|
elevation: 2, |
||||
|
), |
||||
|
child: controller.isLoading.value |
||||
|
? Row( |
||||
|
mainAxisAlignment: MainAxisAlignment.center, |
||||
|
children: [ |
||||
|
SizedBox( |
||||
|
width: 20.w, |
||||
|
height: 20.w, |
||||
|
child: const CircularProgressIndicator( |
||||
|
strokeWidth: 2, |
||||
|
valueColor: AlwaysStoppedAnimation<Color>(Colors.white), |
||||
|
), |
||||
|
), |
||||
|
SizedBox(width: 12.w), |
||||
|
const Text('处理中...'), |
||||
|
], |
||||
|
) |
||||
|
: Row( |
||||
|
mainAxisAlignment: MainAxisAlignment.center, |
||||
|
children: [ |
||||
|
Icon(Icons.payment, size: 20.w), |
||||
|
SizedBox(width: 8.w), |
||||
|
Text( |
||||
|
'发起微信支付', |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.sp, |
||||
|
fontWeight: FontWeight.w600, |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
)); |
||||
|
} |
||||
|
|
||||
|
/// 状态卡片 |
||||
|
Widget _buildStatusCard(bool isDarkMode) { |
||||
|
return Obx(() { |
||||
|
if (controller.paymentStatus.value.isEmpty) { |
||||
|
return const SizedBox.shrink(); |
||||
|
} |
||||
|
|
||||
|
final isError = controller.errorMessage.value.isNotEmpty; |
||||
|
|
||||
|
return Container( |
||||
|
padding: EdgeInsets.all(16.w), |
||||
|
decoration: BoxDecoration( |
||||
|
color: isError |
||||
|
? (isDarkMode ? Colors.red[900] : Colors.red[50]) |
||||
|
: (isDarkMode ? Colors.green[900] : Colors.green[50]), |
||||
|
borderRadius: BorderRadius.circular(12.r), |
||||
|
border: Border.all( |
||||
|
color: isError ? Colors.red[300]! : Colors.green[300]!, |
||||
|
width: 1, |
||||
|
), |
||||
|
), |
||||
|
child: Column( |
||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||
|
children: [ |
||||
|
Row( |
||||
|
children: [ |
||||
|
Icon( |
||||
|
isError ? Icons.error : Icons.check_circle, |
||||
|
color: isError ? Colors.red[600] : Colors.green[600], |
||||
|
size: 20.w, |
||||
|
), |
||||
|
SizedBox(width: 8.w), |
||||
|
Text( |
||||
|
'支付状态', |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.sp, |
||||
|
fontWeight: FontWeight.w600, |
||||
|
color: isError ? Colors.red[600] : Colors.green[600], |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
SizedBox(height: 8.h), |
||||
|
Text( |
||||
|
controller.paymentStatus.value, |
||||
|
style: TextStyle( |
||||
|
fontSize: 14.sp, |
||||
|
color: isDarkMode ? Colors.white : Colors.black, |
||||
|
), |
||||
|
), |
||||
|
if (controller.errorMessage.value.isNotEmpty) ...[ |
||||
|
SizedBox(height: 8.h), |
||||
|
Text( |
||||
|
'错误信息: ${controller.errorMessage.value}', |
||||
|
style: TextStyle( |
||||
|
fontSize: 12.sp, |
||||
|
color: Colors.red[600], |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
SizedBox(height: 12.h), |
||||
|
SizedBox( |
||||
|
width: double.infinity, |
||||
|
child: OutlinedButton( |
||||
|
onPressed: controller.resetStatus, |
||||
|
style: OutlinedButton.styleFrom( |
||||
|
side: BorderSide( |
||||
|
color: isError ? Colors.red[600]! : Colors.green[600]!, |
||||
|
), |
||||
|
), |
||||
|
child: Text( |
||||
|
'重新测试', |
||||
|
style: TextStyle( |
||||
|
color: isError ? Colors.red[600] : Colors.green[600], |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/// 使用说明 |
||||
|
Widget _buildInstructions(bool isDarkMode) { |
||||
|
return Container( |
||||
|
padding: EdgeInsets.all(16.w), |
||||
|
decoration: BoxDecoration( |
||||
|
color: isDarkMode ? Colors.grey[900] : Colors.blue[50], |
||||
|
borderRadius: BorderRadius.circular(12.r), |
||||
|
border: Border.all( |
||||
|
color: Colors.blue[200]!, |
||||
|
width: 1, |
||||
|
), |
||||
|
), |
||||
|
child: Column( |
||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||
|
children: [ |
||||
|
Row( |
||||
|
children: [ |
||||
|
Icon( |
||||
|
Icons.info_outline, |
||||
|
color: Colors.blue[600], |
||||
|
size: 20.w, |
||||
|
), |
||||
|
SizedBox(width: 8.w), |
||||
|
Text( |
||||
|
'使用说明', |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.sp, |
||||
|
fontWeight: FontWeight.w600, |
||||
|
color: Colors.blue[600], |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
SizedBox(height: 12.h), |
||||
|
Text( |
||||
|
'1. 选择测试金额(建议使用0.01元进行测试)\n' |
||||
|
'2. 点击"发起微信支付"按钮\n' |
||||
|
'3. 系统将调用微信支付SDK\n' |
||||
|
'4. 在微信中完成支付流程\n' |
||||
|
'5. 返回应用查看支付结果\n\n' |
||||
|
'注意:这是测试环境,实际不会产生真实扣费', |
||||
|
style: TextStyle( |
||||
|
fontSize: 14.sp, |
||||
|
color: isDarkMode ? Colors.grey[300] : Colors.grey[700], |
||||
|
height: 1.5, |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue