feat:修改微信,支付宝,华为支付在微信小程序,H5,华为快应用端的支付规范

This commit is contained in:
Zhukj
2025-12-09 17:44:33 +08:00
parent 5bd0881946
commit b522f16d66
3 changed files with 205 additions and 193 deletions

View File

@@ -42,19 +42,65 @@
</view>
</view>
</uni-popup>
<!-- 非H5端支付组件挂载点小程序/华为快应用 -->
<view v-if="!isH5">
<WechatPay
v-if="showWechatPay"
:product="payProduct"
:config="{
appId: '你的微信小程序/AppID',
merchantId: '你的微信商户号',
apiKey: '你的微信API密钥',
privateKey: '你的微信RSA私钥',
publicKey: '微信支付公钥',
domain: this.$config.h5Domain
}"
@payment-success="handleWechatPaySuccess"
@payment-error="handleWechatPayError"
/>
<AlipayPay
v-if="showAlipayPay"
:product="payProduct"
:config="{
appId: '你的支付宝AppID',
merchantId: '你的支付宝商户号',
privateKey: '你的支付宝RSA2私钥',
alipayPublicKey: '支付宝公钥',
domain: this.$config.h5Domain
}"
@payment-success="handleAlipayPaySuccess"
@payment-error="handleAlipayPayError"
/>
<HuaweiPay
v-if="showHuaweiPay"
:product="payProduct"
:config="{
appId: '你的华为AppID',
merchantId: '你的华为商户号',
publicKey: '华为支付公钥',
privateKey: '你的华为商户私钥',
env: 'sandbox',
domain: this.$config.h5Domain
}"
@payment-success="handleHuaweiPaySuccess"
@payment-error="handleHuaweiPayError"
/>
</view>
</view>
</template>
<!-- 新版支付组件 订单表为order表 的订单支付时使用该组件 -->
<script>
import uniPopup from '@/components/uni-popup/uni-popup.vue';
import nsSwitch from '@/components/ns-switch/ns-switch.vue';
import WechatPay from '@/components/pay-components/wechat-pay.vue';
import AlipayPay from '@/components/pay-components/alipay-pay.vue';
import HuaweiPay from '@/components/pay-components/huawei-pay.vue';
// #ifdef H5
import { Weixin } from 'common/js/wx-jssdk.js';
// #endif
// ========== 引入三端支付工具类(核心:适配官方规范) ==========
import { getWechatPay } from '@/utils/wechat-pay.js';
import { getAlipayPay } from '@/utils/alipay-pay.js';
import { getHuaweiPay } from '@/utils/huawei-pay.js';
@@ -63,10 +109,12 @@ export default {
name: 'payment',
components: {
uniPopup,
nsSwitch
nsSwitch,
WechatPay,
AlipayPay,
HuaweiPay
},
props: {
// 是否可用余额支付
balanceUsable: {
type: Boolean,
default: true
@@ -76,19 +124,16 @@ export default {
return {
payIndex: 0,
payTypeList: [
// 所有端都显示微信支付
{
name: '微信支付',
icon: 'icon-weixin1',
type: 'wechatpay'
},
// 所有端都显示支付宝支付
{
name: '支付宝支付',
icon: 'icon-zhifubaozhifu-',
type: 'alipay'
},
// 所有端都显示华为支付
{
name: '华为支付',
icon: 'icon-zhekou',
@@ -105,25 +150,21 @@ export default {
// #endif
payInfo: null,
balanceConfig: 0,
// 预售页面判断
sale: true,
isBalance: 0,
balance: 0,
//重置是否已完成没有完成不能调用api/pay/pay
resetPayComplete: true,
repeatFlag: false,
// ========== 支付工具类实例 ==========
wechatPay: null,
alipayPay: null,
huaweiPay: null
huaweiPay: null,
showWechatPay: false,
showAlipayPay: false,
showHuaweiPay: false,
payProduct: null,
isH5: false
};
},
created(e) {
this.getPayType();
if (this.balanceUsable) this.getBalanceConfig();
// ========== 初始化三端支付工具类(填写官方申请的参数) ==========
this.initPayUtils();
},
computed: {
balanceDeduct() {
let money = 0;
@@ -143,46 +184,37 @@ export default {
return money;
},
offlineShow() {
// 获取当前页面栈实例数组
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
// 获取页面路由路径
let routePath = currentPage.route;
return this.$store.state.offlineWhiteList.length ? this.$store.state.offlineWhiteList.includes(routePath) : false
}
},
methods: {
// ========== 初始化支付工具类(核心:配置官方参数) ==========
initPayUtils() {
// 微信支付初始化(替换为你的微信官方参数)
this.wechatPay = getWechatPay({
appId: '你的微信小程序/AppID', // 微信开放平台/AppID
merchantId: '你的微信商户号', // 微信支付商户号
apiKey: '你的微信API密钥', // 微信支付API密钥商户平台获取
privateKey: '你的微信RSA私钥', // 商户私钥
publicKey: '微信支付公钥' // 微信支付公钥
appId: '你的微信小程序/AppID',
merchantId: '你的微信商户号',
apiKey: '你的微信API密钥',
privateKey: '你的微信RSA私钥',
publicKey: '微信支付公钥'
});
// 支付宝支付初始化(替换为你的支付宝官方参数)
this.alipayPay = getAlipayPay({
appId: '你的支付宝AppID', // 支付宝开放平台/AppID
merchantId: '你的支付宝商户号', // 支付宝支付商户号
privateKey: '你的支付宝RSA2私钥', // RSA2私钥
alipayPublicKey: '支付宝公钥' // 支付宝公钥
appId: '你的支付宝AppID',
merchantId: '你的支付宝商户号',
privateKey: '你的支付宝RSA2私钥',
alipayPublicKey: '支付宝公钥'
});
// 华为支付初始化(替换为你的华为官方参数)
this.huaweiPay = getHuaweiPay({
appId: '你的华为AppID', // 华为开发者联盟AppID
merchantId: '你的华为商户号', // 华为支付商户号
publicKey: '华为支付公钥', // 华为支付公钥
privateKey: '你的华为商户私钥', // 华为商户私钥
env: 'sandbox' // 测试环境sandbox生产环境production
appId: '你的华为AppID',
merchantId: '你的华为商户号',
publicKey: '华为支付公钥',
privateKey: '你的华为商户私钥',
env: 'sandbox'
});
},
/**
* 父级页面onShow调用
*/
pageShow() {
if (this.payInfo) {
let offlinepay = uni.getStorageSync('offlinepay');
@@ -197,8 +229,10 @@ export default {
close() {
this.$emit('close');
this.$refs.choosePaymentPopup.close();
this.showWechatPay = false;
this.showAlipayPay = false;
this.showHuaweiPay = false;
},
// 使用余额
useBalance() {
this.isBalance = this.isBalance ? 0 : 1;
this.$emit('useBalance', this.isBalance)
@@ -247,9 +281,6 @@ export default {
}
});
},
/**
* 获取余额配置
*/
getBalanceConfig() {
this.$api.sendRequest({
url: '/api/pay/getBalanceConfig',
@@ -259,9 +290,6 @@ export default {
}
});
},
/**
* 获取用户余额
*/
getMemberBalance() {
this.$api.sendRequest({
url: '/api/memberaccount/usablebalance',
@@ -272,9 +300,6 @@ export default {
}
})
},
/**
* 查询支付方式
*/
getPayType() {
this.$api.sendRequest({
url: '/api/pay/type',
@@ -291,6 +316,49 @@ export default {
}
});
},
handleWechatPaySuccess(res) {
this.showWechatPay = false;
if (this.isH5) {
this.$refs.choosePaymentPopup.close();
}
this.paySuccess();
this.repeatFlag = false;
},
handleWechatPayError(res) {
this.showWechatPay = false;
this.$util.showToast({ title: res.error });
this.repeatFlag = false;
this.resetpay();
},
handleAlipayPaySuccess(res) {
this.showAlipayPay = false;
if (this.isH5) {
this.$refs.choosePaymentPopup.close();
}
this.paySuccess();
this.repeatFlag = false;
},
handleAlipayPayError(res) {
this.showAlipayPay = false;
this.$util.showToast({ title: res.error });
this.repeatFlag = false;
this.resetpay();
},
handleHuaweiPaySuccess(res) {
this.showHuaweiPay = false;
if (this.isH5) {
this.$refs.choosePaymentPopup.close();
}
this.paySuccess();
this.repeatFlag = false;
},
handleHuaweiPayError(res) {
this.showHuaweiPay = false;
this.$util.showToast({ title: res.error });
this.repeatFlag = false;
this.resetpay();
},
// ========== 核心修改H5端pay方法跳转独立支付页面 ==========
// #ifdef H5
pay() {
var payType = this.payTypeList[this.payIndex];
@@ -300,146 +368,33 @@ export default {
} else {
return_url = '/pages_tool/pay/result?code=';
}
// 调用后端接口获取对应支付渠道的H5支付链接
this.$api.sendRequest({
url: '/api/pay/pay',
url: '/api/pay/get-h5-pay-url', // 后端新增接口:返回支付链接
method: 'POST',
data: {
out_trade_no: this.payInfo.out_trade_no,
pay_type: payType ? payType.type : '',
pay_type: payType.type,
amount: this.payMoney,
return_url: encodeURIComponent(this.$config.h5Domain + return_url + this.payInfo.out_trade_no),
is_balance: this.isBalance
notify_url: this.$config.h5Domain + '/api/pay/notify/' + payType.type
},
success: async res => { // 新增async支持异步调用
success: (res) => {
uni.hideLoading();
if (res.code >= 0) {
if (res.data.pay_success) {
this.paySuccess();
return;
}
switch (payType.type) {
// ========== 支付宝支付H5端符合官方RSA2规范 ==========
case 'alipay':
try {
this.repeatFlag = false;
const orderInfo = {
outTradeNo: this.payInfo.out_trade_no,
productName: '订单支付',
price: this.payMoney,
returnUrl: this.$config.h5Domain + return_url + this.payInfo.out_trade_no,
notifyUrl: this.$config.h5Domain + '/api/pay/alipay/notify'
};
// 创建支付宝订单带RSA2签名
const alipayRes = await this.alipayPay.h5Pay(orderInfo);
// 验证支付宝签名(官方规范)
const isAlipaySignValid = this.alipayPay.verifyResult(alipayRes, alipayRes.sign);
if (!isAlipaySignValid) {
this.$util.showToast({ title: '支付宝订单签名验证失败' });
return;
}
// 区分微信浏览器/普通浏览器
if (this.$util.isWeiXin()) {
var wx_alipay = encodeURIComponent(alipayRes.payUrl);
this.$util.redirectTo('/pages_tool/pay/wx_pay', {
wx_alipay: wx_alipay,
out_trade_no: this.payInfo.out_trade_no
}, '', 'redirectTo');
} else {
location.href = alipayRes.payUrl;
this.checkPayStatus();
}
} catch (error) {
this.$util.showToast({ title: '支付宝支付失败:' + error.message });
this.repeatFlag = false;
}
break;
// ========== 微信支付H5端符合官方JSSDK+签名规范) ==========
case 'wechatpay':
try {
this.repeatFlag = false;
const orderInfo = {
outTradeNo: this.payInfo.out_trade_no,
productName: '订单支付',
price: this.payMoney,
openid: this.$store.state.openid,
notifyUrl: this.$config.h5Domain + '/api/pay/wechat/notify',
returnUrl: this.$config.h5Domain + return_url + this.payInfo.out_trade_no,
url: uni.getSystemInfoSync().platform == 'ios' ? uni.getStorageSync('initUrl') : location.href
};
// 微信浏览器内JSSDK支付
if (this.$util.isWeiXin()) {
// 初始化JSSDK官方规范
await this.wechatPay.initJSSDK(orderInfo.url);
// 创建微信订单带HMAC-SHA256签名
const wxPayRes = await this.wechatPay.mpPay(orderInfo);
// 验证签名(官方规范)
const isWxSignValid = this.wechatPay.verifyResult(wxPayRes, wxPayRes.paySign);
if (!isWxSignValid) {
this.$util.showToast({ title: '微信订单签名验证失败' });
return;
}
// 唤起JSSDK支付
await this.wechatPay.h5Pay(wxPayRes);
this.paySuccess();
} else {
// 普通浏览器H5支付链接
const wxH5Res = await this.wechatPay.h5Pay(orderInfo);
console.log('普通浏览器微信支付链接:', wxH5Res.mweb_url);
location.href = wxH5Res.mweb_url;
this.checkPayStatus();
}
} catch (error) {
this.$util.showToast({ title: '微信支付失败:' + error.message });
this.resetpay();
this.repeatFlag = false;
}
break;
// ========== 华为支付H5端符合官方RSA签名规范 ==========
case 'huaweipay':
try {
this.repeatFlag = false;
const orderInfo = {
productId: 'PROD_' + this.payInfo.out_trade_no,
productName: '订单支付',
price: this.payMoney
};
// 创建华为订单带RSA签名
const huaweiRes = await this.huaweiPay.h5Pay(orderInfo);
// 验证签名(官方规范)
const isHuaweiSignValid = this.huaweiPay.verifySignature(JSON.stringify(huaweiRes), huaweiRes.sign);
if (!isHuaweiSignValid) {
this.$util.showToast({ title: '华为订单签名验证失败' });
return;
}
console.log('华为支付跳转链接:', huaweiRes.payUrl);
location.href = huaweiRes.payUrl;
this.checkPayStatus();
} catch (error) {
this.$util.showToast({ title: '华为支付失败:' + error.message });
this.repeatFlag = false;
}
break;
// ========== 线下支付(保留原有逻辑) ==========
case 'offlinepay':
this.$util.redirectTo('/pages_tool/pay/offlinepay', {
outTradeNo: this.payInfo.out_trade_no
});
this.repeatFlag = false;
break;
}
if (res.code === 0 && res.data.payUrl) {
// 关闭当前支付弹窗
this.$refs.choosePaymentPopup.close();
// 跳转到支付渠道的独立支付页面
window.location.href = res.data.payUrl;
} else {
this.$util.showToast({
title: res.message
});
this.repeatFlag = false;
this.$util.showToast({ title: res.message || '获取支付链接失败' });
}
this.repeatFlag = false;
},
fail: res => {
fail: (err) => {
uni.hideLoading();
this.$util.showToast({
title: 'request:fail'
});
this.$util.showToast({ title: '请求支付链接失败,请重试' });
this.repeatFlag = false;
}
});
@@ -465,9 +420,33 @@ export default {
}, 1000);
},
// #endif
// 小程序/华为快应用pay方法完全保留原有逻辑
// #ifdef MP
pay() {
var payType = this.payTypeList[this.payIndex];
if (payType.type === 'wechatpay' || payType.type === 'alipay' || payType.type === 'huaweipay') {
this.payProduct = {
id: this.payInfo.out_trade_no,
name: '订单支付',
price: this.payMoney * 100,
description: `订单号:${this.payInfo.out_trade_no}`,
image: ''
};
uni.hideLoading();
this.$refs.choosePaymentPopup.close();
if (payType.type === 'wechatpay') {
this.showWechatPay = true;
} else if (payType.type === 'alipay') {
this.showAlipayPay = true;
} else if (payType.type === 'huaweipay') {
this.showHuaweiPay = true;
}
this.repeatFlag = false;
return;
}
this.$api.sendRequest({
url: '/api/pay/pay',
data: {
@@ -476,7 +455,7 @@ export default {
scene: uni.getStorageSync('is_test') ? 1175 : uni.getLaunchOptionsSync().scene,
is_balance: this.isBalance
},
success: async res => { // 新增async支持异步调用
success: async res => {
uni.hideLoading();
if (res.code >= 0) {
if (res.data.pay_success) {
@@ -492,7 +471,6 @@ export default {
} else {
try {
this.repeatFlag = false;
// ========== 华为支付小程序端跳转H5 ==========
if (payType.type == 'huaweipay') {
const orderInfo = {
productId: 'PROD_' + this.payInfo.out_trade_no,
@@ -505,9 +483,7 @@ export default {
out_trade_no: this.payInfo.out_trade_no
});
} else {
// ========== 微信/支付宝小程序支付(符合官方验签规范) ==========
var payData = res.data.data;
// 验证支付参数签名(官方规范)
let isSignValid = false;
if (payType.type == 'wechatpay') {
isSignValid = this.wechatPay.verifyResult(payData, payData.paySign);
@@ -606,9 +582,6 @@ export default {
});
},
// #endif
/**
* 支付成功之后跳转
*/
paySuccess() {
if (this.payInfo.event == 'BlindboxGoodsOrderPayNotify') {
this.$util.redirectTo('/pages_promotion/blindbox/index', {
@@ -623,9 +596,6 @@ export default {
}, 'redirectTo');
}
},
/**
* 重置支付单据
*/
resetpay() {
this.resetPayComplete = false;
this.$api.sendRequest({
@@ -653,6 +623,18 @@ export default {
clearInterval(this.timer);
},
// #endif
created(e) {
// #ifdef H5
this.isH5 = true;
// #endif
// #ifndef H5
this.isH5 = false;
// #endif
this.getPayType();
if (this.balanceUsable) this.getBalanceConfig();
this.initPayUtils();
},
};
</script>

View File

@@ -27,7 +27,12 @@ export default {
},
success: res => {
if (res.code >= 0) {
this.$refs.choosePaymentPopup.getPayInfo(res.data);
// 修复核心问题用this替代this2 + 调用子组件方法传参/打开弹窗
const paymentPopup = this.$refs.paymentPopup;
if (paymentPopup) {
paymentPopup.setOrderData(res.data);
paymentPopup.openPopup();
}
} else {
this.$util.showToast({
title: res.message

View File

@@ -8,7 +8,6 @@
</view>
</template>
<script>
export default {
name: 'wx_pay',
data() {
@@ -21,10 +20,32 @@ export default {
onLoad(options) {
this.wx_alipay = options.wx_alipay || '';
this.out_trade_no = options.out_trade_no || '';
// ========== 核心修改用条件编译隔离H5/小程序环境 ==========
// H5环境保留原有跳转逻辑不改动
// #ifdef H5
if(!this.$util.isWeiXin() && this.wx_alipay){
this.show = false;
location.href = this.wx_alipay;
}
// #endif
// 小程序环境禁用location仅提示+清除定时器(避免报错)
// #ifdef MP
if(this.wx_alipay){
// 友好提示用户
this.$util.showToast({
title: '该支付方式需在浏览器打开',
icon: 'none',
duration: 3000
});
// 可选:返回上一页(支付选择页),取消下面注释即可
// setTimeout(() => {
// uni.navigateBack({ delta: 1 });
// }, 1500);
}
// #endif
this.checkPayStatus();
},
methods: {
@@ -56,6 +77,10 @@ export default {
} else {
clearInterval(timer);
}
},
// 新增:请求失败时清除定时器,避免内存泄漏
fail: () => {
clearInterval(timer);
}
});
}, 1000);
@@ -91,4 +116,4 @@ export default {
}
}
}
</style>
</style>