You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

596 lines
18 KiB

import 'package:get/get.dart';
import 'dart:convert';
import 'package:voitrans/data/services/network/api.dart';
import 'package:tobias/tobias.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../modules/login/controllers/weixinLogin.dart';
typedef PaymentResultCallback = void Function(bool success, String message);
/// 支付服务
class PayService extends GetxService {
late FlWX _flwx;
late Tobias _tobias; // 添加 Tobias 实例
String? _lastOrderId; // 最近一次创建的订单号
String? get lastOrderId => _lastOrderId;
@override
void onInit() {
super.onInit();
//微信
FlWX().register(
appSecret: '9ceb39df312b3ba95a229b2aa0d15496',
appId: 'wx4b5ec8957ad5e425',
partnerId: '1719983673',
universalLink: 'https://voitrans.net/app/',
params: FlWXCallbackParams(onHttp: (url) async {
return '';
}));
_flwx = FlWX();
// 初始化支付宝SDK
_tobias = Tobias(); // 初始化 Tobias 实例
_initAlipay();
}
/// 初始化支付宝SDK
Future<void> _initAlipay() async {
try {
// 检查支付宝是否安装 - 修复用法
final isInstalled = await _tobias.isAliPayInstalled;
print('支付宝是否安装: $isInstalled');
} catch (e) {
print('初始化支付宝SDK失败: $e');
}
}
/// 查询支付结果
///
/// [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;
}
}
/// 微信支付
///
/// [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;
}
}
/// 创建微信支付订单
///
/// [productId] 商品ID
/// [productName] 商品名称
/// [productDesc] 商品描述
/// [amount] 支付金额(分)
/// [paymentMethod] 支付方式(1=微信支付)
/// [clientIp] 客户端IP(可选)
/// [notifyUrl] 通知URL(可选)
/// [extraData] 扩展数据(可选)
///
/// 返回支付参数,用于调用 [wechatPay] 方法
Future<Map<String, dynamic>?> createWechatPayOrder({
required String productId,
required String productName,
String? productDesc,
required int amount,
int paymentMethod = 4, // 1表示微信支付
String? clientIp,
String? notifyUrl,
String? extraData,
}) async {
try {
// 调用后端API创建支付订单
final response = await Api.paycreateorder({
'product_id': productId,
'product_name': productName,
'product_desc': productDesc ?? '',
'amount': amount,
'payment_method': paymentMethod,
'client_ip': clientIp ?? '',
'notify_url': notifyUrl ?? '',
'extra_data': extraData ?? '',
});
print('创建支付订单: $response');
// 检查响应是否成功
if (response != null) {
// 尝试提取订单号,兼容多种返回字段
String? orderId;
final candidates = [
'order_id',
'orderId',
'out_trade_no',
'outTradeNo',
];
for (final key in candidates) {
final v = response[key];
if (v is String && v.isNotEmpty) {
orderId = v;
break;
}
}
if (orderId == null && response['data'] is Map<String, dynamic>) {
final data = response['data'] as Map<String, dynamic>;
for (final key in candidates) {
final v = data[key];
if (v is String && v.isNotEmpty) {
orderId = v;
break;
}
}
}
_lastOrderId = orderId;
final pay_params = response["pay_params"] as Map<String, dynamic>;
// 返回微信支付所需的参数
final result = {
'appId': pay_params['appid'],
'partnerId': pay_params['partnerid'],
'prepayId': pay_params['prepayid'],
'packageValue': pay_params['package'] ?? 'Sign=WXPay',
'nonceStr': pay_params['noncestr'],
'timestamp': pay_params['timestamp'],
'sign': pay_params['sign'],
};
if (orderId != null) {
result['orderId'] = orderId;
}
return result;
} else {
print('创建支付订单失败: ${response?['message'] ?? '未知错误'}');
return null;
}
} catch (e) {
print('创建支付订单异常: $e');
return null;
}
}
Future<bool> processWechatPayment({
required String productId,
required int amount,
required String description,
String? userId,
PaymentResultCallback? onResult,
}) async {
try {
// 1. 创建支付订单
final paymentData = await createWechatPayOrder(
productId: productId,
productName: '会员充值',
productDesc: '1个月会员服务',
amount: 1, // 29.99元,单位:分
paymentMethod: 4, // 微信支付
notifyUrl: 'https://api.ideapsound.com/api/home/pay_wechatnotify',
);
if (paymentData == null) {
onResult?.call(false, '创建支付订单失败');
return false;
}
// 2. 调用微信支付
return await wechatPay(
paymentData: paymentData,
onResult: onResult,
);
} catch (e) {
onResult?.call(false, '支付流程异常: $e');
return false;
}
}
/// 完整的支付宝支付流程
///
/// [productId] 产品ID
/// [amount] 支付金额(分)
/// [description] 商品描述
/// [onResult] 支付结果回调
Future<bool> processAlipayPayment({
required String productId,
required int amount,
required String description,
PaymentResultCallback? onResult,
}) async {
try {
// 检查支付宝是否安装
final isInstalled = await _tobias.isAliPayInstalled;
if (!isInstalled) {
onResult?.call(false, '支付宝未安装');
return false;
}
// 调用现有的 createAlipayOrder 方法创建订单
final orderInfo = await createAlipayOrder(
productId: productId,
productName: description,
productDesc: description,
amount: amount,
paymentMethod: 3, // 支付宝支付
notifyUrl: 'https://api.ideapsound.com/api/home/pay_alipaynotify',
);
if (orderInfo == null) {
onResult?.call(false, '创建支付订单失败');
return false;
}
print('支付宝支付订单: $orderInfo');
// 调用支付宝支付
final result = await _tobias.pay(orderInfo);
print('支付宝支付结果: $result');
// 处理支付结果
if (result != null) {
final resultStatus = result['resultStatus'] as String?;
final memo = result['memo'] as String?;
if (resultStatus == '9000') {
onResult?.call(true, '支付成功');
return true;
} else {
onResult?.call(false, memo ?? '支付失败');
return false;
}
} else {
onResult?.call(false, '支付结果为空');
return false;
}
} catch (e) {
onResult?.call(false, '支付异常: $e');
return false;
}
}
/// 支付宝支付
///
/// [orderInfo] 支付宝订单信息字符串
/// [onResult] 支付结果回调
Future<bool> alipay({
required String orderInfo,
PaymentResultCallback? onResult,
}) async {
try {
// 检查支付宝是否安装 - 使用实例方法
final isInstalled = await _tobias.isAliPayInstalled;
if (!isInstalled) {
onResult?.call(false, '支付宝未安装');
return false;
}
// 调用支付宝支付 - 使用实例方法
final result = await _tobias.pay(orderInfo);
if (result != null) {
// 解析支付结果
final resultStatus = result['resultStatus'] as String?;
final memo = result['memo'] as String?;
if (resultStatus == '9000') {
// 支付成功
onResult?.call(true, '支付成功');
return true;
} else {
// 支付失败或取消
onResult?.call(false, memo ?? '支付失败');
return false;
}
} else {
onResult?.call(false, '支付结果为空');
return false;
}
} catch (e) {
onResult?.call(false, '支付异常: $e');
return false;
}
}
/// 创建支付宝支付订单
///
/// [productId] 商品ID
/// [productName] 商品名称
/// [productDesc] 商品描述
/// [amount] 支付金额(分)
/// [paymentMethod] 支付方式(2=支付宝)
/// [clientIp] 客户端IP(可选)
/// [notifyUrl] 通知URL(可选)
/// [extraData] 扩展数据(可选)
///
/// 返回支付宝订单信息字符串,用于调用 [alipay] 方法
Future<String?> createAlipayOrder({
required String productId,
required String productName,
String? productDesc,
required int amount,
int paymentMethod = 3, // 2表示支付宝
String? clientIp,
String? notifyUrl,
String? extraData,
}) async {
try {
// 调用后端API创建支付订单
final response = await Api.paycreateorder({
'product_id': productId,
'product_name': productName,
'product_desc': productDesc ?? '',
'amount': amount,
'payment_method': paymentMethod,
'client_ip': clientIp ?? '',
'notify_url': notifyUrl ?? '',
'extra_data': extraData ?? '',
});
print('创建支付宝订单: $response');
// 检查响应是否成功
if (response != null && response['alipay_pay_params'] != null) {
// 解析订单号并缓存
String? orderId;
final candidates = [
'order_id',
'orderId',
'out_trade_no',
'outTradeNo',
];
for (final key in candidates) {
final v = response[key];
if (v is String && v.isNotEmpty) {
orderId = v;
break;
}
}
if (orderId == null && response['data'] is Map<String, dynamic>) {
final data = response['data'] as Map<String, dynamic>;
for (final key in candidates) {
final v = data[key];
if (v is String && v.isNotEmpty) {
orderId = v;
break;
}
}
}
_lastOrderId = orderId;
// 返回支付宝订单信息字符串
return response['alipay_pay_params'] as String?;
} else {
print('创建支付宝订单失败: ${response?['message'] ?? '未知错误'}');
return null;
}
} catch (e) {
print('创建支付宝订单异常: $e');
return null;
}
}
/// 创建 PayPal 支付订单
/// 返回需要打开的支付授权链接(approval_url)或支付页面URL
Future<String?> createPaypalOrder({
required String productId,
required String productName,
String? productDesc,
required int amount,
int paymentMethod = 5, // 约定:5 表示 PayPal
String? clientIp,
String? notifyUrl,
String? extraData,
}) async {
try {
final response = await Api.paycreateorder({
'product_id': productId,
'product_name': productName,
'product_desc': productDesc ?? '',
'amount': amount,
'payment_method': paymentMethod,
'client_ip': clientIp ?? '',
'notify_url': notifyUrl ?? '',
'extra_data': extraData ?? '',
});
if (response != null) {
// 1) 提取并缓存平台订单号(用于回查)
String? appOrderId;
const candidates = [
'order_id',
'orderId',
'out_trade_no',
'outTradeNo',
];
for (final key in candidates) {
final v = response[key];
if (v is String && v.isNotEmpty) {
appOrderId = v;
break;
}
}
final data = response['data'];
if (appOrderId == null && data is Map<String, dynamic>) {
for (final key in candidates) {
final v = data[key];
if (v is String && v.isNotEmpty) {
appOrderId = v;
break;
}
}
}
_lastOrderId = appOrderId; // 记录APP侧订单号(如 APP2025...),用于 pay_askorder
// 2) 优先解析 paypal_pay_params 字段(后端返回JSON字符串,含 links)
String? rawParams;
final topParams = response['paypal_pay_params'];
final dataParams =
(data is Map<String, dynamic>) ? data['paypal_pay_params'] : null;
if (topParams is String && topParams.isNotEmpty) {
rawParams = topParams;
} else if (dataParams is String && dataParams.isNotEmpty) {
rawParams = dataParams;
}
if (rawParams != null) {
try {
final parsed = jsonDecode(rawParams);
if (parsed is Map<String, dynamic>) {
final links = parsed['links'];
if (links is List) {
for (final item in links) {
if (item is Map) {
final rel = item['rel']?.toString();
final hrefRaw = item['href']?.toString();
if (rel == 'approve' &&
hrefRaw != null &&
hrefRaw.isNotEmpty) {
// 清理日志中可能出现的反引号等噪音字符
final href = hrefRaw.replaceAll('`', '').trim();
return href;
}
}
}
}
}
} catch (e) {
print('解析 paypal_pay_params 失败: $e');
}
}
// 3) 回退:尝试从常见字段直接取URL
final urlKeys = [
'paypal_pay_url',
'approval_url',
'paypalApprovalUrl',
'pay_url',
'payment_url',
'url',
];
for (final key in urlKeys) {
final url = response[key];
if (url is String && url.isNotEmpty) {
return url;
}
}
if (data is Map<String, dynamic>) {
for (final key in urlKeys) {
final url = data[key];
if (url is String && url.isNotEmpty) {
return url;
}
}
}
}
print('创建 PayPal 订单失败或未返回有效URL: $response');
return null;
} catch (e) {
print('创建 PayPal 订单异常: $e');
return null;
}
}
/// 拉起 PayPal 支付(打开授权链接)。
/// 注意:该方法仅负责跳转至 PayPal 页面,结果需要后端回调通知。
Future<bool> paypalPay({
required String approvalUrl,
PaymentResultCallback? onResult,
}) async {
try {
final uri = Uri.parse(approvalUrl);
final ok = await launchUrl(uri, mode: LaunchMode.externalApplication);
if (ok) {
onResult?.call(true, '已打开 PayPal,请完成支付');
} else {
onResult?.call(false, '无法打开 PayPal 支付页面');
}
return ok;
} catch (e) {
onResult?.call(false, '打开 PayPal 异常: $e');
return false;
}
}
/// 一体化的 PayPal 支付流程:创建订单 -> 打开授权链接
Future<bool> processPaypalPayment({
required String productId,
required int amount,
required String description,
PaymentResultCallback? onResult,
}) async {
try {
final approvalUrl = await createPaypalOrder(
productId: productId,
productName: description,
productDesc: description,
amount: amount,
paymentMethod: 5,
notifyUrl: 'https://api.ideapsound.com/api/home/pay_paypalnotify',
);
if (approvalUrl == null) {
onResult?.call(false, '创建 PayPal 订单失败');
return false;
}
return await paypalPay(approvalUrl: approvalUrl, onResult: onResult);
} catch (e) {
onResult?.call(false, 'PayPal 支付流程异常: $e');
return false;
}
}
}