Browse Source

上传代码

newdev_shunjiawei
liwei1dao 1 year ago
parent
commit
fa3a675cfa
  1. 175
      lib/data/services/pay_service.dart
  2. 9
      lib/modules/payment/bindings/payment_binding.dart
  3. 85
      lib/modules/payment/controllers/payment_controller.dart
  4. 365
      lib/modules/payment/views/payment_view.dart
  5. 23
      lib/modules/settings/views/settings_view.dart
  6. 9
      lib/routes/app_pages.dart
  7. 3
      lib/routes/app_routes.dart

175
lib/data/services/pay_service.dart

@ -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;
}
}
}

9
lib/modules/payment/bindings/payment_binding.dart

@ -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());
}
}

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

@ -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;
}
}

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

@ -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,
),
),
],
),
);
}
}

23
lib/modules/settings/views/settings_view.dart

@ -516,6 +516,29 @@ class SettingsView extends GetView<SettingsController> {
// : Colors.grey[200]),
// //BLE测试
// 支付测试
_buildSimpleNavigationSetting(
title: '支付测试',
subtitle: '测试微信支付功能',
icon: Icons.payment,
iconBgColor: isDarkMode
? Colors.green[900]!.withOpacity(0.3)
: Colors.green[100]!,
iconColor:
isDarkMode ? Colors.green[300]! : Colors.green[600]!,
titleColor: isDarkMode ? Colors.white : null,
subtitleColor: isDarkMode ? Colors.white70 : null,
onTap: () {
Get.toNamed(Routes.payment);
},
isDarkMode: isDarkMode,
),
Divider(
height: 1,
color: isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.grey[200]),
Obx(() => controller.showDebugInfo.value
? _buildSimpleNavigationSetting(
title: 'opus解码测试',

9
lib/routes/app_pages.dart

@ -63,6 +63,8 @@ import '../modules/music/views/music_playlist_view.dart';
import '../modules/music/bindings/music_playlist_binding.dart';
import '../modules/FTFTranslation/bindings/FTFTranslation_binding.dart';
import '../modules/FTFTranslation/views/FTFTranslation_view.dart';
import '../modules/payment/bindings/payment_binding.dart';
import '../modules/payment/views/payment_view.dart';
abstract class AppPages {
static final pages = [
@ -288,5 +290,12 @@ abstract class AppPages {
page: () => const QqmusicPlaylistView(),
binding: QQMusicPlaylistBinding(),
),
GetPage(
name: Routes.payment,
page: () => const PaymentView(),
binding: PaymentBinding(),
transition: Transition.rightToLeft,
transitionDuration: Duration(milliseconds: 250),
),
];
}

3
lib/routes/app_routes.dart

@ -63,4 +63,7 @@ abstract class Routes {
static const ble = '/ble';
// ble设备管理
static const qqmusic = '/qqmusic';
// 支付相关
static const payment = '/payment'; // 支付测试页面
}

Loading…
Cancel
Save