MatchMaster/server/laf-cloud/functions/wx/iosgetPayInfo.ts
2026-08-07 10:59:22 +08:00

210 lines
7.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import cloud from '@lafjs/cloud'
import crypto from 'crypto';
import * as JungleConfigModule from "@/jungleConfig";
const JungleConfig: any = JungleConfigModule as any;
const mchid = "1719895437";//商户id
const serialNo = "2A97ED6ED441E55600EBC8830B9EC889ED41496E";//证书序列号
const db = cloud.database();
const ThinkingData = require('thinkingdata-node');
export default async function (ctx: FunctionContext) {
let outTradeNo = ctx.body.outTradeNo;
if (!outTradeNo) {
return { code: 0, data: null, msg: "未获取到充值订单" };
}
const uid = ctx.body.uid;
let res = await getOrder(outTradeNo);
console.log("查询充值结果");
let ret = await db.collection("order").where({ "outTradeNo": outTradeNo }).getOne();
let iosOrder = cloud.shared.get("iosOrder"); // 获取 wsMap
if (!ret.data) {
console.error("ios找不到充值订单" + outTradeNo);
return { code: 0, data: null, msg: "未获取到充值信息" };
}
if (ret.data.state == 2) {
console.error("ios已经获取奖励");
return { code: 0, data: null, msg: "已经获取到奖励" };
}
let payment_name = ret.data?.itemid;
if (res) {
let paidUser: any = null;
if (uid) {
let res1 = await db.collection("users").where({ _id: uid }).getOne();
if (!res1.data) {
return { code: 0, data: null, msg: "未获取到玩家数据" };
}
paidUser = res1.data;
if (!iosOrder) {
iosOrder = {};
} else {
//console.log(iosOrder);
}
if (!iosOrder[outTradeNo]) {
sead(ret.data, res1.data, getClientIp(ctx));
iosOrder[outTradeNo] = 2;
} else {
}
cloud.shared.set("iosOrder", iosOrder); // 设置 wsMap
// 保留原有充值处理流程Jungle 解锁逻辑在后面独立追加。
switch (payment_name) {
case "month_Card":
let monthCardTime = res1.data.monthCardTime;
if (!monthCardTime || monthCardTime < Date.now()) {
monthCardTime = Date.now();
}
monthCardTime = monthCardTime + 2592000000;
let ret = await db.collection("users").where({ _id: uid }).update({ monthCardTime: monthCardTime, monthCardReward: 0, pay_user: true });
break;
case "reborn_Gift":
db.collection("users").where({ _id: uid }).update({ rebornGiftTime: Date.now(), rebornGiftCount: 1, pay_user: true });
break;
case "starter_pack":
db.collection("users").where({ _id: uid }).update({ starter_packState: 1, pay_user: true });
break;
default:
db.collection("users").where({ _id: uid }).update({ pay_user: true });
break;
}
}
// 保持原有订单完成逻辑不变,所有商品仍然正常进入 state=2。
await db.collection("order").where({ outTradeNo: outTradeNo }).update({ state: 2, chargeTime: new Date(Date.now() + 8 * 3600000), getTime: new Date(Date.now() + 8 * 3600000) });
// Jungle 属于附加逻辑;异常只记录日志,不影响上面的原充值流程和成功返回。
if (paidUser) {
try {
const jungleTier = JungleConfig.getJunglePaidTierByProductId(payment_name);
if (jungleTier) {
const unlockResult = JungleConfig.unlockJungleTierByProductId(
paidUser.jungleTreasureState,
payment_name,
outTradeNo,
);
if (unlockResult.ok && unlockResult.changed && unlockResult.state) {
await db.collection("users").where({ _id: uid }).update({
jungleTreasureState: JungleConfig.serializeJungleState(unlockResult.state),
});
}
}
} catch (error) {
console.error("ios Jungle 付费档位解锁失败,不影响原充值结果", error);
}
}
return { code: 1, data: { goodsPrice: ret.data?.goodsPrice, payment_name: payment_name }, msg: "充值成功" };
} else {
console.log("充值不成功:" + outTradeNo);
return { code: 0, data: { goodsPrice: ret.data?.goodsPrice, payment_name: payment_name }, msg: "充值失败" };
}
}
const getClientIp = (req) => {
return (
req.headers['x-forwarded-for']?.split(',')[0]?.trim() || // 代理链中的第一个 IP
req.headers['x-real-ip'] || // Nginx 配置的 real-ip
req.socket.remoteAddress // 原始 IP可能是代理
);
};
/**获取订单*/
async function getOrder(outTradeNo) {
const url = `https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/${outTradeNo}?mchid=1719895437`;
const nonceStr = crypto.randomBytes(16).toString('hex');
const timestamp = Math.floor(Date.now() / 1000).toString();
let au = await sign(outTradeNo, nonceStr, timestamp);
let res = await fetch(url, {
method: 'GET', // 默认是 GET可省略
headers: {
'Authorization': au, // 认证令牌
'Content-Type': 'application/json', // 声明请求体类型GET 请求通常不需要)
'Accept': 'application/json', // 声明期望的响应类型
}
})
const data = await res.json();
if (data.trade_state == 'SUCCESS') {
return true;
} else {
return false;
}
}
async function sign(outTradeNo, nonceStr, timestamp) {
const data = `GET\n/v3/pay/transactions/out-trade-no/${outTradeNo}?mchid=1719895437\n${timestamp}\n${nonceStr}\n\n`
// 创建签名对象
const sign = crypto.createSign('RSA-SHA256');
// 更新签名内容
sign.update(data);
// 获取存储桶
const bucket = cloud.storage.bucket('j3k323ol-colorblock-oss');
// 获取文件列表
const res = await bucket.readFile('apiclient_key.pem');
const privateKeyPem = await res.Body.transformToString();
// 使用私钥签名PKCS1 填充)
const signature = sign.sign({
key: privateKeyPem,
padding: crypto.constants.RSA_PKCS1_PADDING
}, 'base64');
// 构建Authorization头
const authorization = `WECHATPAY2-SHA256-RSA2048 mchid="${mchid}",nonce_str="${nonceStr}",signature="${signature}",timestamp="${timestamp}",serial_no="${serialNo}"`;
return authorization;
}
async function sead(order, userInfo, ip) {
if (!userInfo.distinctId) {
return;
}
let id = '95993f9ab6f1402a87abe5147827e5e0';
if (userInfo.isDebug != "true") {
id = '40e3d5c5f2af49a4a074205564ce5dbb';
}
let teSDK = ThinkingData.initWithBatchMode(id, 'https://data.nika4fun.com/sync_data', {
dryRun: false, // report data to TE or not
deviceId: "123456789",//设备唯一标识
});
let trackEvent = {
accountId: order.openid,
distinctId: userInfo.distinctId,//访客id
event: 'payment',
time: new Date(Date.now() + 8 * 3600000),
ip: ip,
properties: {
order_id: order.outTradeNo,
pay_amount: order.goodsPrice,
payment_name: order.itemid,
payment_num: order.itemCount,
payment_type: "ios_old",
is_on_table: Number(userInfo.addLevel) >= 5,
current_level: userInfo.levelAmount, //当前关卡等级 number
current_health: userInfo.healthAmount, //当前体力值
tmp_coin: userInfo.coinAmount,//当前金币
version: "1.6",
user_id: userInfo._id, //用户id
pay_user: userInfo.pay_user,
register_time: userInfo.register_time,
abTest_layer_one: getABTestGroupValue(userInfo.abTests, "layer_1"),
abTest_layer_two: getABTestGroupValue(userInfo.abTests, "layer_2"),
abTest_layer_three: getABTestGroupValue(userInfo.abTests, "layer_3")
},
callback(e) {
if (e) {
console.log(e);
}
}
};
teSDK.track(trackEvent);
teSDK.close();
return;
}
function getABTestGroupValue(abTests: any, layerKey: string) {
if (!abTests) {
return 0;
}
if (typeof abTests === "string") {
try {
abTests = JSON.parse(abTests);
} catch {
return 0;
}
}
const groupMap = { A: 1, B: 2, C: 3, D: 4, E: 5 };
const group = String(abTests[layerKey]?.group || "").toUpperCase();
return groupMap[group] || 0;
}