Files
yusheng-h5/until/wxpay.js
2026-01-08 16:06:53 +08:00

267 lines
7.1 KiB
JavaScript
Raw Permalink 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.

// utils/wxpay.js
const API_BASE_URL = 'https://yourdomain.com/api';
class WxPay {
constructor() {
this.isWeixin = this.checkWeixin();
this.openid = uni.getStorageSync('wx_openid') || '';
}
// 检查是否在微信环境
checkWeixin() {
const ua = navigator.userAgent.toLowerCase();
return ua.indexOf('micromessenger') !== -1;
}
// 获取 URL 参数
getQueryParam(name) {
const reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
const r = window.location.search.substr(1).match(reg);
if (r != null) return decodeURIComponent(r[2]);
return null;
}
// 微信授权获取 code
async wxAuth() {
if (!this.isWeixin) {
uni.showToast({ title: '请在微信中打开', icon: 'none' });
return null;
}
const code = this.getQueryParam('code');
if (!code) {
// 跳转微信授权
const currentUrl = encodeURIComponent(window.location.href.split('#')[0]);
const authUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${this.appId}&redirect_uri=${currentUrl}&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect`;
window.location.href = authUrl;
return null;
}
return code;
}
// 通过 code 获取 openid
async getOpenId(code) {
try {
const response = await uni.request({
url: `${API_BASE_URL}/wx/auth`,
method: 'GET',
data: { code }
});
if (response[1].data.code === 0) {
const { openid } = response[1].data.data;
this.openid = openid;
uni.setStorageSync('wx_openid', openid);
return openid;
}
return null;
} catch (error) {
console.error('获取openid失败:', error);
return null;
}
}
// 初始化微信 JS-SDK
async initWxJsSDK() {
if (!this.isWeixin) return false;
try {
// 获取当前页面 URL去掉 # 后面的部分)
const currentUrl = window.location.href.split('#')[0];
const response = await uni.request({
url: `${API_BASE_URL}/jssdk/config`,
method: 'GET',
data: { url: encodeURIComponent(currentUrl) }
});
if (response[1].data.code === 0) {
const config = response[1].data.data;
// 引入微信 JS-SDK
await this.loadWxJsSDK();
// 配置微信 JS-SDK
wx.config({
debug: false, // 开启调试模式
appId: config.appId,
timestamp: config.timestamp,
nonceStr: config.nonceStr,
signature: config.signature,
jsApiList: [
'chooseWXPay',
'onMenuShareTimeline',
'onMenuShareAppMessage',
'scanQRCode'
]
});
return new Promise((resolve) => {
wx.ready(() => {
console.log('微信 JS-SDK 初始化成功');
resolve(true);
});
wx.error((err) => {
console.error('微信 JS-SDK 初始化失败:', err);
uni.showToast({ title: '微信初始化失败', icon: 'none' });
resolve(false);
});
});
}
return false;
} catch (error) {
console.error('初始化JS-SDK失败:', error);
return false;
}
}
// 动态加载微信 JS-SDK
loadWxJsSDK() {
return new Promise((resolve, reject) => {
if (typeof wx !== 'undefined') {
resolve();
return;
}
const script = document.createElement('script');
script.src = 'https://res.wx.qq.com/open/js/jweixin-1.6.0.js';
script.onload = resolve;
script.onerror = reject;
document.head.appendChild(script);
});
}
// 创建支付订单
async createPayment(orderData) {
try {
// 确保有 openid
if (!this.openid) {
const code = await this.wxAuth();
if (code) {
await this.getOpenId(code);
}
}
if (!this.openid) {
throw new Error('获取用户信息失败');
}
const response = await uni.request({
url: `${API_BASE_URL}/wxpay/unifiedorder`,
method: 'POST',
header: { 'Content-Type': 'application/json' },
data: {
openid: this.openid,
body: orderData.body || '账户充值',
total_fee: orderData.amount,
out_trade_no: orderData.orderNo,
attach: orderData.attach || ''
}
});
if (response[1].data.code === 0) {
return response[1].data.data;
} else {
throw new Error(response[1].data.msg || '创建订单失败');
}
} catch (error) {
console.error('创建支付订单失败:', error);
throw error;
}
}
// 发起微信支付
async launchPayment(payData) {
return new Promise((resolve, reject) => {
wx.chooseWXPay({
timestamp: payData.timeStamp,
nonceStr: payData.nonceStr,
package: payData.package,
signType: payData.signType,
paySign: payData.paySign,
success: (res) => {
if (res.errMsg === 'chooseWXPay:ok') {
resolve({ success: true, message: '支付成功' });
} else {
reject(new Error('支付失败: ' + res.errMsg));
}
},
fail: (err) => {
reject(new Error('支付失败: ' + JSON.stringify(err)));
},
cancel: () => {
reject(new Error('用户取消支付'));
}
});
});
}
// 完整的支付流程
async pay(amount, orderNo, attach = '') {
try {
// 1. 检查环境
if (!this.isWeixin) {
uni.showToast({ title: '请在微信中打开', icon: 'none' });
return { success: false, message: '非微信环境' };
}
// 2. 初始化 JS-SDK
const initSuccess = await this.initWxJsSDK();
if (!initSuccess) {
return { success: false, message: '微信初始化失败' };
}
// 3. 创建支付订单
const payData = await this.createPayment({
amount: amount,
orderNo: orderNo,
attach: attach
});
// 4. 发起支付
const result = await this.launchPayment(payData);
// 5. 验证支付结果
if (result.success) {
// 支付成功,可以查询订单确认
await this.verifyPayment(orderNo);
return { success: true, message: '支付成功' };
}
return result;
} catch (error) {
console.error('支付流程错误:', error);
return {
success: false,
message: error.message || '支付失败'
};
}
}
// 验证支付结果
async verifyPayment(orderNo) {
try {
const response = await uni.request({
url: `${API_BASE_URL}/wxpay/query`,
method: 'GET',
data: { out_trade_no: orderNo }
});
if (response[1].data.code === 0) {
const orderData = response[1].data.data;
if (orderData.trade_state === 'SUCCESS') {
return true;
}
}
return false;
} catch (error) {
console.error('验证支付结果失败:', error);
return false;
}
}
}
export default new WxPay();