import { requestByGET, requestByPOST } from "@/utils/request";
const { default: WebTracking } = require("@/utils/webTracking");
Component({
/**
* 组件的属性列表
*/
properties: {
// 可以添加外部传入的属性
showNavigation: {
type: Boolean,
value: true,
},
title: {
type: String,
value: "开通会员",
},
},
/**
* 组件的初始数据
*/
data: {
selectedCard: "", // 默认选择第一个卡片
currentPrice: 0, // 当前价格
bidData: [], // 标讯数据
cardList: [], // 金额卡片列表
loading: false,
wxChat:
"https://lianqiai-public.oss-accelerate.aliyuncs.com/app/vip/ic_wxChat.svg",
ic_ok:
"https://lianqiai-public.oss-accelerate.aliyuncs.com/app/vip/ic_ok.svg",
openID: "",
transactionObserver: null, // 保存交易观察者引用
},
/**
* 组件的方法列表
*/
methods: {
/**
* 组件初始化
*/
init() {
// 初始化已处理的交易记录
this.processedTransactions = {}; // 已处理的交易ID
this.verifiedReceipts = {}; // 已验证的收据
this.loadBidData();
this.initialize();
},
// 简单的哈希函数,用于生成字符串的哈希值
simpleHash: function (str) {
if (!str) return "empty";
let hash = 0;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash = hash & hash; // 转换为32位整数
}
return Math.abs(hash).toString();
},
/**
* 加载标讯数据
*/
loadBidData() {
this.setData({
loading: true,
});
// 调用 /goods/bid/list 接口
requestByGET(
{ type: "VIP_DATA" },
"/goods/bid/list",
(res) => {
console.log("标讯数据加载成功:", res);
if (res && res.data) {
// 处理金额卡片数据
const cardList = this.processCardData(res.data);
// 找到第一个可购买的卡片作为默认选择
const firstBuyableCard = cardList.find((card) => card.canBuy);
this.setData({
bidData: res.data.bidList || [],
cardList: cardList,
selectedCard: firstBuyableCard ? firstBuyableCard.code : "",
currentPrice: firstBuyableCard
? firstBuyableCard.discountPrice || firstBuyableCard.price
: 0,
loading: false,
});
console.log(this.data.cardList);
} else {
// 如果没有数据,显示空状态
this.setData({
bidData: [],
cardList: [],
selectedCard: "",
currentPrice: 0,
loading: false,
});
}
},
(err) => {
console.error("标讯数据加载失败:", err);
// 加载失败时显示空状态
this.setData({
bidData: [],
cardList: [],
selectedCard: "",
currentPrice: 0,
loading: false,
});
}
);
},
/**
* 处理金额卡片数据
*/
processCardData(data) {
return data
.map((card) => {
// 计算每天价格
const price = parseFloat(card.discountPrice || card.price);
let dailyPrice = 0;
if (card.code === "SVIP_data_year_1") {
// 年卡:价格除以365天
dailyPrice = (price / 365).toFixed(2);
} else {
// 月卡:价格除以30天
dailyPrice = (price / 30).toFixed(2);
}
console.log(`卡片 ${card.name} 价格计算:`, {
originalPrice: card.price,
discountPrice: card.discountPrice,
usedPrice: price,
dailyPrice: dailyPrice,
code: card.code,
});
return {
id: card.id,
name: card.name,
code: card.code,
price: card.price,
discountPrice: card.discountPrice,
description: card.description,
canBuy: card.canBuy,
tag: card.tag,
discount: card.discount,
expireTime: card.expireTime,
functionTag: card.functionTag,
itemCode: card.itemCode,
daysLeft: card.daysLeft,
dailyPrice: dailyPrice,
appleProductId: card.appleProductId, // 添加Apple产品ID字段
};
})
.reverse(); // 倒序排列
},
/**
* 选择会员卡片
*/
selectCard(e) {
const cardCode = e.currentTarget.dataset.code;
const selectedCard = this.data.cardList.find(
(card) => card.code === cardCode
);
if (selectedCard && selectedCard.canBuy) {
console.log("选中卡片:", {
code: selectedCard.code,
name: selectedCard.name,
price: selectedCard.discountPrice || selectedCard.price,
appleProductId: selectedCard.appleProductId, // 记录Apple产品ID
});
this.setData({
selectedCard: cardCode,
currentPrice: selectedCard.discountPrice || selectedCard.price,
});
} else if (selectedCard && !selectedCard.canBuy) {
// 如果卡片不可购买,显示提示
wx.showToast({
title: "该套餐暂不可购买",
icon: "none",
});
}
},
/**
* 处理支付
*/
handlePayment() {
const { selectedCard, currentPrice, cardList } = this.data;
const selectedCardData = this.data.cardList.find(
(card) => card.code === selectedCard
);
if (!selectedCardData) {
wx.showToast({
title: "请选择会员套餐",
icon: "none",
});
return;
}
// 检查选中的卡片是否可以购买
if (!selectedCardData.canBuy) {
wx.showToast({
title: "该套餐暂不可购买",
icon: "none",
});
return;
}
console.log("选中的卡片信息:", {
code: selectedCardData.code,
name: selectedCardData.name,
price: currentPrice,
originalPrice: selectedCardData.price,
discountPrice: selectedCardData.discountPrice,
});
// #if IOS || ANDROID
this.createOrder(selectedCardData.code);
// #elif MP
let that = this;
wx.login({
success(res) {
console.log(res.code);
that.setData(
{
openID: res.code,
},
() => {
// setData 完成之后再调用 createOrder
that.createOrder(selectedCardData.code, that.data.openID);
}
);
},
});
// #endif
},
createOrder(code, opne_id) {
let path;
let params;
// #if IOS || ANDROID
path = "/order/createAppOrder";
params = {
goodsCode: code,
quantity: 1,
paymentMethod: "WECHAT",
};
// #elif MP
path = "/order/createMnpOrder";
params = {
goodsCode: code,
quantity: 1,
paymentMethod: "WECHAT",
code: opne_id,
};
// #endif
requestByPOST(
params,
path,
(res) => {
console.log("createOrder res: ", res, path);
const prepayId = "prepay_id=" + res.data.prepayId;
// #if IOS || ANDROID
wx.miniapp.requestPayment({
timeStamp: res.data.timestamp,
mchId: res.data.partnerId,
prepayId: res.data.prepayId,
package: res.data.packageValue,
nonceStr: res.data.nonceStr,
sign: res.data.sign,
success: (res) => {
console.warn("wx.miniapp.requestPayment success:", res);
// 触发支付成功事件
// this.triggerEvent("paySuccess", { result: res });
wx.showToast({
title: "支付成功",
icon: "none",
});
setTimeout(() => {
wx.navigateBack();
}, 2000);
},
fail: (res) => {
console.error("fail res:", res);
wx.showToast({
title: "取消支付",
icon: "none",
});
// 触发支付失败事件
this.triggerEvent("payFail", { result: res });
},
complete: (res) => {
console.error("complete res:", res);
},
});
// #elif MP
wx.requestPayment({
timeStamp: res.data.timestamp,
nonceStr: res.data.nonceStr,
package: prepayId,
signType: res.data.signType,
paySign: res.data.paySign,
orderNo: res.data.orderId,
appId: res.data.appId,
success(res) {
console.log("createOrder success res: ", res);
// 触发支付成功事件
// this.triggerEvent("paySuccess", { result: res });
wx.showToast({
title: "支付成功",
icon: "none",
});
setTimeout(() => {
wx.navigateBack();
}, 2000);
WebTracking.log("支付成功");
},
fail(res) {
console.log("createOrder fail: ", res);
wx.showToast({
title: "取消支付",
icon: "none",
});
// 触发支付失败事件
this.triggerEvent("payFail", { result: res });
},
});
// #endif
},
(err) => {
console.error("createOrder err: ", err);
// 触发支付失败事件
this.triggerEvent("payFail", { error: err });
}
);
},
/**
* 处理支付逻辑
*/
processPayment(selectedCardData) {
const { selectedCard, currentPrice } = this.data;
console.log("开始支付,卡片code:", selectedCardData.code);
wx.showLoading({
title: "正在支付...",
});
// 这里可以调用支付接口,传递code参数
// 目前只支持微信支付
setTimeout(() => {
wx.hideLoading();
wx.showToast({
title: "支付成功",
icon: "success",
duration: 2000,
});
// 支付成功后可以跳转到其他页面或刷新数据
setTimeout(() => {
wx.navigateBack();
}, 2000);
}, 1500);
},
//IOSAPP支付观察者
initialize: function () {
console.log("初始化交易观察者");
// 如果已经存在观察者,先移除
if (this.data.transactionObserver) {
this.removeTransactionObserver();
}
const ob = {
updatedTransactions: (args) => {
console.log("处理交易状态更新,例如购买成功或失败。:", args);
console.log(
"收到的交易数量:",
args.transactions ? args.transactions.length : 0
);
args.transactions.forEach((item, index) => {
console.log(`处理第 ${index + 1} 个交易:`, item.transactionState);
this.handleTransaction(item);
});
},
restoreCompletedTransactionsFailedWithError: (args) => {
console.log("处理恢复购买时出现的错误。", args);
},
paymentQueueRestoreCompletedTransactionsFinished: (args) => {
console.log("在恢复购买交易完成时调用。", args);
},
shouldAddStorePayment: (args) => {
console.log("询问是否应该添加商店付款。", args);
},
paymentQueueDidChangeStorefront: (args) => {
console.log("处理 App Store 店面变化。", args);
},
didRevokeEntitlementsForProductIdentifiers: (args) => {
console.log("处理撤销某些产品的权限。", args);
},
};
// 保存观察者引用
this.setData({
transactionObserver: ob,
});
// 添加观察者
wx.miniapp.IAP.addTransactionObserver(ob);
},
//ios支付按钮
handlePaymentIOS() {
// 获取选中的卡片数据
const { selectedCard, cardList } = this.data;
const selectedCardData = cardList.find(
(card) => card.code === selectedCard
);
console.log(selectedCardData.appleProductId);
if (!selectedCardData) {
wx.showToast({
title: "请选择会员套餐",
icon: "none",
});
return;
}
wx.showLoading({
title: "加载中",
});
let that = this;
const requestObj = wx.miniapp.IAP.requestSKProducts({
productIdentifiers: [selectedCardData.appleProductId],
success(ret) {
console.log(ret.invalidProductIdentifiers, "我是393",ret.products);
// 先创建苹果订单,获取orderUuid
that.createAppleOrder(selectedCardData.code, ret.products);
},
fail(error) {
console.error(`requestSKProducts failed. ${error}`);
wx.hideLoading();
},
});
wx.miniapp.IAP.cancelRequestSKProducts(requestObj);
},
// 创建苹果订单
createAppleOrder: function (goodsCode, products) {
const params = {
goodsCode: goodsCode,
quantity: 1,
paymentMethod: "APPLE",
};
requestByPOST(
params,
"/order/createAppleAppOrder",
(res) => {
console.log("createAppleOrder success: ", res);
if (res && res.data && res.data.orderUuid) {
// 创建订单成功,开始支付流程
this.startPayment(null, products, res.data.orderUuid);
} else {
console.error("创建苹果订单失败: 未获取到orderUuid");
wx.hideLoading();
wx.showToast({
title: "订单创建失败",
icon: "none",
});
}
},
(err) => {
console.error("createAppleOrder error: ", err);
wx.hideLoading();
wx.showToast({
title: "订单创建失败",
icon: "none",
});
}
);
},
//IOSAPP支付请求结果
startPayment: function (err, productIdentifier, orderUuid) {
if (err) {
wx.showToast({
title: err,
icon: "none",
});
wx.hideLoading();
return;
}
wx.miniapp.IAP.addPaymentByProductIdentifiers({
productIdentifier: productIdentifier[0].productIdentifier,
applicationUsername: orderUuid,
success: (args) => {
console.log("拉起支付成功", args);
// wx.hideLoading();
},
fail: (args) => {
console.error("拉起支付失败", args);
// wx.hideLoading();
},
});
},
//IOSAPP处理交易
handleTransaction: function (transaction) {
console.log( "处理交易状态:",transaction.transactionState,"交易ID:", transaction.transactionIdentifier);
// 创建更可靠的交易唯一标识
let transactionKey;
if (transaction.transactionIdentifier) {
// 如果有交易ID,使用交易ID + 状态
transactionKey =
transaction.transactionIdentifier +
"_" +
transaction.transactionState;
} else if (transaction.transactionReceipt) {
// 如果没有交易ID但有收据,使用收据的哈希值 + 状态
transactionKey =
this.simpleHash(transaction.transactionReceipt) +
"_" +
transaction.transactionState;
} else {
// 如果都没有,使用时间戳 + 状态(最后的兜底方案)
transactionKey = Date.now() + "_" + transaction.transactionState;
console.warn("交易缺少标识符,使用时间戳作为标识:", transactionKey);
}
console.log("生成的交易标识:", transactionKey);
// 在观察者层面阻断重复处理同一交易
if (this.processedTransactions[transactionKey]) {
console.log("交易已处理过,跳过重复处理:", transactionKey);
return;
}
// 标记交易为已处理
this.processedTransactions[transactionKey] = true;
console.log("标记交易为已处理:", transactionKey);
if (
transaction.transactionState === "SKPaymentTransactionStatePurchased" ||
transaction.transactionState === "SKPaymentTransactionStateRestored"
) {
console.log(transaction.transactionReceipt, "订单收据");
this.finishTransaction(null, transaction);
} else if (
transaction.transactionState === "SKPaymentTransactionStateFailed"
) {
this.finishTransaction("交易失败", transaction);
} else if (
transaction.transactionState === "SKPaymentTransactionStateDeferred"
) {
this.finishTransaction("等待外部操作", transaction);
}
},
//IOSAPP处理结束交易的结果。
finishTransaction: function (err, transaction) {
if (err) {
wx.showToast({
title: err,
icon: "none",
});
return;
}
wx.miniapp.IAP.finishTransaction({
transactionIdentifier: transaction.transactionIdentifier,
success: (args) => {
console.log("完成交易 success", args);
// 调用苹果支付验证接口
this.verifyApplePayment(transaction.transactionReceipt);
},
fail: (args) => {
console.error("完成交易 fail", args);
wx.hideLoading();
},
});
},
// 验证苹果支付凭据
verifyApplePayment: function (transactionReceipt) {
console.log("开始验证苹果支付凭据", transactionReceipt);
console.log("收据类型:", typeof transactionReceipt);
console.log(
"收据长度:",
transactionReceipt ? transactionReceipt.length : "undefined"
);
// 双重保护:检查收据是否已经验证过
const receiptHash = this.simpleHash(transactionReceipt);
if (this.verifiedReceipts[receiptHash]) {
console.log("收据已验证过,跳过重复验证:", receiptHash);
return;
}
// 标记收据为正在验证
this.verifiedReceipts[receiptHash] = true;
console.log("标记收据为验证中:", receiptHash);
const params = {
receipt: transactionReceipt,
};
// 调用验证接口
requestByPOST(
params,
"/appleIap/verify",
(res) => {
console.log("苹果支付验证结果: ", res);
wx.hideLoading();
if (res && res.code === 200 && res.data === true) {
// 验证成功,下发权益成功
wx.showToast({
title: "支付成功",
icon: "none",
});
setTimeout(() => {
wx.navigateBack();
}, 2000);
} else {
// 验证失败或下发权益失败
wx.showToast({
title: "下发权益失败,请联系客服",
icon: "none",
duration: 3000,
});
}
},
(err) => {
console.error("苹果支付验证失败: ", err);
wx.hideLoading();
wx.showToast({
title: "下发权益失败,联系客服",
icon: "none",
duration: 3000,
});
}
);
},
//IOSAPP恢复交易列表
restoreTransactions: function (callback) {
wx.miniapp.IAP.restoreCompletedTransactions({
success: (transactions) => {
console.log("恢复的交易", transactions);
callback(null, transactions);
},
fail: (error) => {
console.error("恢复交易失败", error);
callback(error);
},
});
},
//IOSAPP交易收据
getReceiptURL: function () {
let that = this;
ReceiptURL({
success: (url) => {
console.log("交易收据 URL", url);
that.getReceiptData(null, url);
},
fail: (error) => {
console.error("获取收据 URL 失败", error);
that.getReceiptData("获取收据 URL 失败");
},
});
},
getReceiptData: function (err) {
if (err) {
wx.showToast({
title: err,
icon: "none",
});
return;
}
wx.miniapp.IAP.getAppStoreReceiptData({
success: (data) => {
console.log("交易收据数据", data);
// 调用后端接口传送交易数据
},
fail: (error) => {
console.error("获取收据数据失败", error);
},
});
},
//IOSAPP刷新收据结果
refreshReceipt: function (err, callback) {
if (err) {
wx.showToast({
title: err,
icon: "none",
});
return;
}
wx.miniapp.IAP.requestSKReceiptRefreshRequest({
success: (args) => {
console.log("刷新收据成功", args);
callback(null, args);
},
fail: (error) => {
console.error("刷新收据失败", error);
callback(error);
},
});
},
// 移除交易观察者
removeTransactionObserver: function () {
if (this.data.transactionObserver) {
console.log("移除交易观察者");
// 正确的移除方式:直接传递观察者对象
wx.miniapp.IAP.removeTransactionObserver(this.data.transactionObserver);
this.setData({
transactionObserver: null,
});
}
// 清理验证状态
if (this.processedTransactions) {
this.processedTransactions = {};
}
if (this.verifiedReceipts) {
this.verifiedReceipts = {};
}
},
/**
* 刷新数据
*/
refresh() {
this.loadBidData();
},
/**
* 返回上一页
*/
goBack() {
wx.navigateBack();
},
},
/**
* 组件生命周期
*/
lifetimes: {
attached() {
this.init();
},
detached() {
this.removeTransactionObserver();
},
},
});
handlePaymentIO 从这个按钮开始看
915

被折叠的 条评论
为什么被折叠?



