import cloud from '@lafjs/cloud' const token = "nika123"; const EncodingAESKey = "XcdOFaZOQjmyBqYHxWAITtrmq11YaZQ63DeEZAAgYJt"; const mchid = "1719895437";//商户id const serialNo = "2A97ED6ED441E55600EBC8830B9EC889ED41496E";//证书序列号 const appid = "wx30f74367b3d3e7a6"; import crypto from 'crypto'; const db = cloud.database(); export default async function (ctx: FunctionContext) { console.log(ctx.body); //console.log(ctx.query);; try { let openid = ctx.body.FromUserName; //console.log(openid); const data = JSON.parse(ctx.body.SessionFrom); //console.log(data); console.log(data); if (data.tpye == "ios") { await PostMsg(openid, "点击下方页面进行充值"); await PostImg(openid, data.outTradeNo, data.propName, data.count, data.price); } } catch (e) { console.error("ios客服充值参数错误:" + ctx.body.SessionFrom); console.log(ctx.body); } //return ctx.query.echostr; return { data: "scuess" }; } /**获取订单*/ async function getOrder(openid, toatal, outTradeNo, timestamp, nonceStr) { const url = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi"; // 生成随机字符串和时间戳 const body = { "appid": appid, "mchid": mchid, "description": "消消王者道具购买", "out_trade_no": outTradeNo, "notify_url": "https://q6rvwvtnga.sealoshzh.site/wx/iosPayCall", "amount": { "total": Number(toatal), "currency": "CNY" }, "payer": { "openid": openid } } let ret = await sign(nonceStr, timestamp, body); const res = await fetch(url, { method: 'POST', headers: { 'Authorization': ret, 'Accept': 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify(body) }) if (res.ok) { const data = await res.json().catch(async () => { //如果不是JSON,尝试读取文本 return await res.text().catch(() => 'Empty response'); }); return data.prepay_id; } return null; } async function sign(nonceStr, timestamp, body) { const data = `POST\n/v3/pay/transactions/jsapi\n${timestamp}\n${nonceStr}\n${JSON.stringify(body)}\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 frontsign(data) { // 创建签名对象 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(); //console.error(privateKeyPem); // 使用私钥签名(PKCS1 填充) const signature = sign.sign({ key: privateKeyPem, padding: crypto.constants.RSA_PKCS1_PADDING }, 'base64'); // 构建Authorization头 return signature } const propName = { gold_1: "金币包1", gold_2: "金币包2", gold_3: "金币包3", gold_4: "金币包4", gold_5: "金币包5", gold_6: "金币包6", unlimited_health_bundle_1: "无限体力组合包1", unlimited_health_bundle_2: "无限体力组合包2", unlimited_health_bundle_3: "无限体力组合包3", freeze_in_game: "局内购买冻结", hammer_in_game: "局内购买锤子", wand_in_gamerefill: "局内购买魔棒", health: "补满体力" }; async function PostMsg(OpenId, msg) { let token = cloud.shared.get('wxaccess_token'); if (!token) { return { code: 0, data: null, msg: "token获取失败" }; } const url = `https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=${token}`; const data = { "touser": OpenId, "msgtype": "text", "text": { "content": msg } } const res = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json;charset=utf-8' }, body: JSON.stringify(data) }) return "ok" } async function PostImg(OpenId, outTradeNo, name, count, price) { let token = cloud.shared.get('wxaccess_token'); if (!token) { return { code: 0, data: null, msg: "token获取失败" }; } const url = `https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=${token}`; const nonceStr = crypto.randomBytes(16).toString('hex'); const timestamp = Math.floor(Date.now() / 1000).toString(); const total = count * price; let prepay_id = await getOrder(OpenId, total, outTradeNo, timestamp, nonceStr); let frontBody = { "appId": appid, //公众号ID,由商户传入 "timeStamp": timestamp, //时间戳,自1970年以来的秒数 "nonceStr": nonceStr, //随机串 "package": "prepay_id=" + prepay_id } const data1 = `${frontBody.appId}\n${frontBody.timeStamp}\n${frontBody.nonceStr}\n${frontBody.package}\n`; let paySign = await frontsign(data1); let user = await db.collection("users").where({ openid: OpenId }).update({ iosTime: frontBody.timeStamp }); let param = { name: propName[name], openid: OpenId, outTradeNo: outTradeNo, time: timestamp, quantity: count, price: price, body: { "appId": frontBody.appId, //公众号ID,由商户传入 "timeStamp": frontBody.timeStamp, //时间戳,自1970年以来的秒数 "nonceStr": frontBody.nonceStr, //随机串 "package": frontBody.package, "signType": "RSA", //微信签名方式: "paySign": paySign //微信签名 } } await db.collection("iosOrder").add({ openid: OpenId, outTradeNo: outTradeNo, itemid: name, itemCount: count, goodsPrice: Number(price), time: Date.now(), orderTime: new Date(Date.now() + 8 * 3600000), chargeTime: 0, getTime: 0, type: "ios", state: 0, }); const data = { "touser": OpenId, "msgtype": "link", "link": { "title": "点我支付", "description": "金额:" + (total / 100).toFixed(2) + "元", "url": `https://pay.nika4games.com/order3.html#data=${encodeURIComponent(JSON.stringify(param))}`, "thumb_url": "https://static-host-j3k323ol-colorblock-oss.sealoshzh.site/icon.jpg" } } //console.log(data); const res = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json;charset=utf-8' }, body: JSON.stringify(data) }) const data11 = await res.json(); console.log(data11); if (data11.errcode == 40001) { console.error("未获取到正确token,重新发送请求"); let res = await getWxToken(); await PostMsg(OpenId, "点击下方页面进行充值"); await PostImg(OpenId, outTradeNo, name, count, price); } return "ok" } /**获取微信Token*/ async function getWxToken() { const api_url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appid}&secret=${appsecret}`; const ret = await cloud.fetch({ url: api_url, method: "get", }); if (ret?.data?.access_token) { cloud.shared.set('wxaccess_token', ret.data.access_token); return ret.data.access_token; } else { //access_token = nul l; return null; } }