412 lines
11 KiB
Vue
412 lines
11 KiB
Vue
<template>
|
||
<view class="wrapper" style="height: 100vh">
|
||
<!-- 浏览器不支持提示 -->
|
||
<view class="wrapper" id="pay-result" style="background: #fff" v-if="envErrType">
|
||
<view class="pay-result-container">
|
||
<image src="/static/image/payerr.png" style="width: 96px; height: 96px"></image>
|
||
<view class="env-err-text">{{ envErrText }}</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="wrapper" id="pay-result" style="background: #fff" v-else-if="orderInfo.status === 2">
|
||
<view class="pay-result-container">
|
||
<image v-if="browerEnv === 'alipay'" src="/static/image/ali-payok.png" style="width: 96px; height: 96px"></image>
|
||
<image v-if="browerEnv === 'weixin'" src="/static/image/wx-payok.png" style="width: 96px; height: 96px"></image>
|
||
<view class="pay-result-text">支付已完成</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 支付页面 -->
|
||
<view class="wrapper" id="pay-page" v-else-if="currentPage === 'pay-page'">
|
||
<view class="item-name">{{ orderInfo.goodsName }}</view>
|
||
<view class="item-count">
|
||
<text style="font-size: 26px">¥ </text>{{ numberFormat(orderInfo.totalFee) }}
|
||
</view>
|
||
<!-- <view class="company">重庆八条科技有限公司</view> -->
|
||
|
||
<!-- 支付按钮 -->
|
||
<view class="pay-methods">
|
||
<view v-for="item in payMethodList" :key="item.id" class="pay-method-item">
|
||
<view class="pay-method-item-left">
|
||
<image :src="item.logo" style="width: 30px; height: 30px"></image>
|
||
<text class="pay-method-name">{{ item.name }}</text>
|
||
</view>
|
||
<view class="pay-method-item-right">
|
||
<image :src="item.checkIcon" style="width: 18px; height: 18px"></image>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<button id="pay-btn" :class="[`${browerEnv}-btn`]" @click="goPay">
|
||
立即支付
|
||
</button>
|
||
</view>
|
||
|
||
<!-- 支付结果页面 -->
|
||
<view class="wrapper" id="pay-result" style="background: #fff" v-else-if="currentPage === 'pay-result'">
|
||
<view class="pay-result-container">
|
||
<image :src="payResultItem.icon" style="width: 96px; height: 96px"></image>
|
||
<view class="pay-result-text">{{ payResultItem.resultText }}</view>
|
||
<button v-if="fromApp" class="back-btn" open-type="launchApp" app-parameter="wechat" :binderror="launchAppError">返回APP</button>
|
||
<button v-else class="back-btn" :style="payResultItem.style" @click="goBackPay">
|
||
{{ payResultItem.backText }}
|
||
</button>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import request from "@/lib/request.js";
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
authCode: '',
|
||
encOrderId: "",
|
||
outTradeNo: "",
|
||
browerEnv: "",
|
||
orderInfo: {},
|
||
currentPage: "pay-page",
|
||
paySuccess: true,
|
||
payMethodList: [{
|
||
name: "支付宝支付",
|
||
id: "alipay",
|
||
logo: "/static/image/ali-logo.png",
|
||
checkIcon: "/static/image/ali-check.png",
|
||
},
|
||
{
|
||
name: "微信支付",
|
||
id: "weixin",
|
||
logo: "/static/image/wx-logo.png",
|
||
checkIcon: "/static/image/wx-check.png",
|
||
},
|
||
],
|
||
timer: null,
|
||
fromApp: false,
|
||
};
|
||
},
|
||
computed: {
|
||
payResultList() {
|
||
return [{
|
||
icon: "/static/image/payerr.png",
|
||
resultText: "抱歉,订单支付失败",
|
||
backText: "重新支付",
|
||
style: {background: this.browerEnv === "weixin" ? '#05bf5e' : '#2c78fe', color: '#fff'},
|
||
},
|
||
{
|
||
icon: this.browerEnv === "weixin" ?
|
||
"/static/image/wx-payok.png" : "/static/image/ali-payok.png",
|
||
resultText: "支付成功",
|
||
backText: "返回",
|
||
},
|
||
];
|
||
},
|
||
payResultItem() {
|
||
return this.paySuccess ? this.payResultList[1] : this.payResultList[0];
|
||
},
|
||
envErrType() {
|
||
if(!this.browerEnv) return '';
|
||
if (this.browerEnv === "browser") {
|
||
return "envErr:browser";
|
||
} else if (!this.encOrderId && !this.outTradeNo) {
|
||
return "envErr:noParams";
|
||
} else {
|
||
return ''
|
||
}
|
||
},
|
||
envErrText() {
|
||
const group = {
|
||
"envErr:browser": "不支持浏览器,请使用支付宝或微信重新扫码",
|
||
"envErr:noParams": "请通过扫描二维码使用小程序",
|
||
"envErr:outTradeNo": "获取订单信息失败",
|
||
};
|
||
return group[this.envErrType];
|
||
},
|
||
},
|
||
methods: {
|
||
launchAppError(e) {
|
||
console.log(e.detail.errMsg)
|
||
},
|
||
numberFormat(value) {
|
||
if (value) return value.toFixed(2);
|
||
return "0.00";
|
||
},
|
||
// 获取支付宝用户信息
|
||
getAliUserInfo() {
|
||
// 检查是否已授权
|
||
// #ifdef MP-ALIPAY
|
||
my.getAuthCode({
|
||
scopes: ["auth_base"],
|
||
success: (res) => {
|
||
console.log("获取授权码成功", res);
|
||
this.authCode = res.authCode;
|
||
},
|
||
fail: (error) => {
|
||
console.error("获取授权码失败", error);
|
||
uni.showToast({
|
||
icon: "none",
|
||
title: "获取授权码失败",
|
||
});
|
||
},
|
||
});
|
||
// #endif
|
||
},
|
||
// 获取微信用户信息
|
||
getWxUserInfo() {
|
||
// #ifdef MP-WEIXIN
|
||
uni.getProvider({
|
||
service: 'oauth',
|
||
success: (res) => {
|
||
console.log('getProvider', res.provider)
|
||
uni.login({
|
||
provider: res.provider,
|
||
success: (loginRes) => {
|
||
this.authCode = loginRes.code
|
||
console.log('loginRes', this.authCode)
|
||
}
|
||
})
|
||
}
|
||
})
|
||
// #endif
|
||
},
|
||
// 支付按钮点击事件
|
||
async goPay() {
|
||
uni.showLoading()
|
||
try {
|
||
// 应用下单
|
||
const {
|
||
outTradeNo,
|
||
paySource = "jsapi"
|
||
} = this.orderInfo;
|
||
let extra = {};
|
||
// #ifdef MP-ALIPAY
|
||
extra.alipayAuthCode = this.authCode;
|
||
// #endif
|
||
// #ifdef MP-WEIXIN
|
||
extra.weixinAuthCode = this.authCode;
|
||
// #endif
|
||
console.log('authCode',this.authCode)
|
||
if (!this.authCode) {
|
||
console.error("没有授权码");
|
||
return;
|
||
}
|
||
let orderData = await this.handleOrder({
|
||
outTradeNo,
|
||
payType: this.browerEnv,
|
||
paySource: paySource,
|
||
extra,
|
||
});
|
||
let tradeNo = orderData.tradeNo;
|
||
console.log("tradeNo", tradeNo);
|
||
if(this.browerEnv === 'alipay') {
|
||
// 调起支付宝支付
|
||
let res = await this.handleAlipay({
|
||
tradeNO: tradeNo,
|
||
});
|
||
|
||
console.log('支付宝支付成功', res)
|
||
} else if(this.browerEnv === 'weixin') {
|
||
let res = await this.handleWechatPay(orderData);
|
||
|
||
console.log('微信支付成功', res)
|
||
}
|
||
|
||
|
||
// 支付成功
|
||
let orderRes = await this.getOrderInfo()
|
||
this.currentPage = "pay-result";
|
||
if (orderRes.status === 2) {
|
||
this.paySuccess = true;
|
||
// clearInterval(this.timer)
|
||
// this.timer = null
|
||
} else {
|
||
this.paySuccess = false;
|
||
}
|
||
uni.hideLoading()
|
||
} catch (error) {
|
||
console.log('error', error)
|
||
this.currentPage = "pay-result";
|
||
this.paySuccess = false; // 失败
|
||
uni.hideLoading()
|
||
}
|
||
},
|
||
// 查询订单
|
||
async getOrderInfo() {
|
||
let res = await request({
|
||
url: "/api/pay/order",
|
||
method: "GET",
|
||
data: {
|
||
encOrderId: this.encOrderId,
|
||
outTradeNo: this.outTradeNo
|
||
},
|
||
});
|
||
const data = {
|
||
...res.data,
|
||
totalFee: res.data.totalFee / 100,
|
||
};
|
||
return data;
|
||
},
|
||
// 应用下单
|
||
async handleOrder(data) {
|
||
let res = await request({
|
||
url: "/api/pay/order",
|
||
method: "POST",
|
||
data: data,
|
||
});
|
||
console.log("handleOrder", res.data);
|
||
return res.data || {};
|
||
},
|
||
|
||
// 微信支付处理
|
||
handleWechatPay(payParams) {
|
||
return new Promise((resolve, reject) => {
|
||
// 在Uniapp中,可以使用uni.requestPayment API
|
||
uni.requestPayment({
|
||
provider: "wxpay",
|
||
timeStamp: payParams.timeStamp,
|
||
nonceStr: payParams.nonceStr,
|
||
package: payParams.package,
|
||
signType: payParams.signType,
|
||
paySign: payParams.paySign,
|
||
success: (res) => {
|
||
console.log("支付成功:", res);
|
||
resolve();
|
||
},
|
||
fail: (err) => {
|
||
console.error("支付失败:", err);
|
||
reject(new Error("支付失败"));
|
||
},
|
||
});
|
||
});
|
||
},
|
||
|
||
// 支付宝支付处理
|
||
handleAlipay(payParams) {
|
||
console.log("支付宝支付处理");
|
||
return new Promise((resolve, reject) => {
|
||
// 在Uniapp中,可以使用uni.requestPayment API
|
||
uni.requestPayment({
|
||
provider: "alipay",
|
||
orderInfo: payParams.tradeNO, // 支付宝交易号
|
||
success: (res) => {
|
||
if (res.resultCode === "9000") {
|
||
console.log("支付成功", res);
|
||
// 建议以后端异步通知或主动查询订单状态为准
|
||
resolve();
|
||
} else {
|
||
console.log("支付处理中或失败", res);
|
||
// 处理其他结果码
|
||
resolve();
|
||
}
|
||
},
|
||
fail: (err) => {
|
||
console.error("支付失败:", err);
|
||
reject(new Error("支付失败"));
|
||
},
|
||
});
|
||
});
|
||
},
|
||
|
||
async goBackPay() {
|
||
this.orderInfo = await this.getOrderInfo();
|
||
this.currentPage = "pay-page";
|
||
},
|
||
// 获取URL参数
|
||
getQuery() {
|
||
const pages = getCurrentPages();
|
||
const currentPage = pages[pages.length - 1];
|
||
const options = currentPage.options || {};
|
||
return options;
|
||
},
|
||
// 判断浏览器环境是微信/支付宝/普通浏览器
|
||
getBrowserEnv() {
|
||
// 非H5环境,根据平台判断
|
||
// #ifdef MP-WEIXIN
|
||
return "weixin";
|
||
// #endif
|
||
|
||
// #ifdef MP-ALIPAY
|
||
return "alipay";
|
||
// #endif
|
||
},
|
||
extractUrlParams(url) {
|
||
if (!url) {
|
||
return {};
|
||
}
|
||
|
||
// 使用正则表达式解析URL参数,兼容支付宝环境
|
||
const params = {};
|
||
const queryString = url.split("?")[1];
|
||
|
||
if (queryString) {
|
||
const pairs = queryString.split("&");
|
||
for (let i = 0; i < pairs.length; i++) {
|
||
const pair = pairs[i].split("=");
|
||
const key = decodeURIComponent(pair[0]);
|
||
const value = decodeURIComponent(pair[1] || "");
|
||
params[key] = value;
|
||
}
|
||
}
|
||
|
||
return params;
|
||
},
|
||
},
|
||
async onShow() {
|
||
console.log("on Show");
|
||
// 支付宝
|
||
// #ifdef MP-ALIPAY
|
||
if (my) {
|
||
let res = my.getLaunchOptionsSync();
|
||
console.log("res", res);
|
||
const qrCode = res.query ? res.query.qrCode : '';
|
||
let {
|
||
encOrderId
|
||
} = this.extractUrlParams(qrCode);
|
||
if (encOrderId) {
|
||
this.encOrderId = encOrderId;
|
||
this.orderInfo = await this.getOrderInfo();
|
||
}
|
||
this.getAliUserInfo()
|
||
}
|
||
// #endif
|
||
},
|
||
async onLoad(options) {
|
||
console.log("options", options);
|
||
|
||
const env = this.getBrowserEnv();
|
||
console.log('env', env)
|
||
this.browerEnv = env;
|
||
if (env === "browser") return;
|
||
|
||
// 过滤支付方式,只显示当前环境支持的支付方式
|
||
this.payMethodList = this.payMethodList.filter((item) => item.id === env);
|
||
|
||
// #ifdef MP-WEIXIN
|
||
if(options.q) { // q: 二维码地址
|
||
let {
|
||
encOrderId
|
||
} = this.extractUrlParams(decodeURIComponent(options.q));
|
||
console.log('encOrderId', encOrderId)
|
||
if (encOrderId) {
|
||
this.encOrderId = encOrderId;
|
||
this.orderInfo = await this.getOrderInfo();
|
||
}
|
||
}
|
||
if(options.outTradeNo) {
|
||
// app进入的
|
||
this.fromApp = true;
|
||
this.outTradeNo = options.outTradeNo;
|
||
this.orderInfo = await this.getOrderInfo();
|
||
}
|
||
console.log('encOrderId', this.encOrderId)
|
||
console.log('outTradeNo', this.outTradeNo)
|
||
this.getWxUserInfo()
|
||
// #endif
|
||
},
|
||
};
|
||
</script>
|
||
|
||
<style>
|
||
@import url("/static/app.css");
|
||
</style> |