2026-03-24 11:45:13 +08:00
|
|
|
<template>
|
|
|
|
|
<view class="pay-page">
|
|
|
|
|
<!-- 自定义导航栏 -->
|
|
|
|
|
<custom-navbar
|
|
|
|
|
title="支付订单"
|
|
|
|
|
:showBack="true"
|
|
|
|
|
backgroundColor="#FFFFFF"
|
|
|
|
|
></custom-navbar>
|
|
|
|
|
|
|
|
|
|
<!-- 支付金额 -->
|
|
|
|
|
<view class="amount-section">
|
|
|
|
|
<image src="/static/images/pay_icon.png"
|
|
|
|
|
mode="aspectFit"
|
|
|
|
|
class="pay_icon"></image>
|
|
|
|
|
<view class="amount">
|
|
|
|
|
<text class="symbol">¥</text>
|
|
|
|
|
<text class="value">{{ orderInfo.pay_money }}</text>
|
|
|
|
|
</view>
|
|
|
|
|
<!-- <view class="countdown">支付剩余时间: {{ countdown }}</view> -->
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
<!-- 支付方式 -->
|
|
|
|
|
<view class="method-section">
|
|
|
|
|
<view class="section-title">选择支付方式</view>
|
|
|
|
|
<view class="method-list">
|
|
|
|
|
<view
|
|
|
|
|
class="method-item"
|
|
|
|
|
v-for="(item, index) in methodList"
|
|
|
|
|
:key="index"
|
|
|
|
|
@click="selectMethod(item)"
|
|
|
|
|
>
|
|
|
|
|
<view class="method-info">
|
|
|
|
|
<image :src="item.icon" mode="aspectFit" class="method-icon"></image>
|
|
|
|
|
<text class="method-name">{{item.name}}</text>
|
|
|
|
|
</view>
|
|
|
|
|
<agree-radio :isAgree="item.selected"></agree-radio>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
<!-- 底部支付按钮 -->
|
|
|
|
|
<view class="footer">
|
|
|
|
|
<view class="total-amount">
|
|
|
|
|
<view class="amount-money">
|
|
|
|
|
<text class="symbol">¥</text>
|
|
|
|
|
<text class="amount">{{ orderInfo.pay_money }}</text>
|
|
|
|
|
</view>
|
|
|
|
|
<text class="amount-lable">应付金额</text>
|
|
|
|
|
</view>
|
|
|
|
|
<view class="pay-btn" @click="confirmPay">确认支付</view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
import customNavbar from '@/components/custom-navbar/custom-navbar.vue'
|
|
|
|
|
import { debounce } from '../../utils/debounce';
|
|
|
|
|
import request from '@/utils/request'
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
components: {
|
|
|
|
|
customNavbar
|
|
|
|
|
},
|
|
|
|
|
data() {
|
|
|
|
|
return {
|
|
|
|
|
orderInfo: {
|
|
|
|
|
id: '',
|
|
|
|
|
pay_money: '',
|
|
|
|
|
number: ''
|
|
|
|
|
},
|
|
|
|
|
serverTitle: '',
|
|
|
|
|
// countdown: '00:29:58',
|
|
|
|
|
selectedPayment: 'wechat',
|
|
|
|
|
balance: '98489.98',
|
|
|
|
|
timer: null,
|
|
|
|
|
isPay: false,
|
|
|
|
|
methodList: [
|
|
|
|
|
{
|
|
|
|
|
id: 1,
|
|
|
|
|
name: '微信',
|
|
|
|
|
payment: 'wechat',
|
|
|
|
|
icon: '/static/images/wechat.png',
|
|
|
|
|
selected: true
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 2,
|
|
|
|
|
name: '支付宝',
|
|
|
|
|
payment: 'alipay',
|
|
|
|
|
icon: '/static/images/alipay.png',
|
|
|
|
|
selected: false
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
onLoad(options) {
|
|
|
|
|
// this.getUserInfo();
|
|
|
|
|
console.log(options)
|
|
|
|
|
if (options.id) {
|
|
|
|
|
this.orderInfo.id = options.id;
|
|
|
|
|
this.orderInfo.number = options.number;
|
|
|
|
|
this.orderInfo.pay_money = options.money;
|
|
|
|
|
this.serverTitle = options.title;
|
|
|
|
|
console.log(this.orderInfo)
|
|
|
|
|
// this.startCountdown()
|
|
|
|
|
// this.getOrderInfo()
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
onUnload() {
|
|
|
|
|
if (this.timer) {
|
|
|
|
|
clearInterval(this.timer)
|
|
|
|
|
this.timer = null
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
methods: {
|
|
|
|
|
getUserInfo() {
|
|
|
|
|
request.post('/user/getuser',{type: 1}).then(result=>{
|
|
|
|
|
this.address.name = result.data.username;
|
|
|
|
|
this.address.phone = result.data.account;
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
// 获取订单信息
|
|
|
|
|
async getOrderInfo() {
|
|
|
|
|
try {
|
|
|
|
|
const res = await request.post('/order/detail', {
|
|
|
|
|
id: this.orderInfo.id
|
|
|
|
|
})
|
|
|
|
|
if (res.code === 0) {
|
|
|
|
|
this.orderInfo = res.data
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('获取订单信息失败:', error)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
// 选择支付方式
|
|
|
|
|
selectMethod(item) {
|
|
|
|
|
this.selectedPayment = item.payment;
|
|
|
|
|
this.methodList.forEach(method => {
|
|
|
|
|
method.selected = method.id === item.id
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
// 开始倒计时
|
|
|
|
|
startCountdown() {
|
|
|
|
|
let time = 30 * 60 // 30分钟
|
|
|
|
|
this.timer = setInterval(() => {
|
|
|
|
|
time--
|
|
|
|
|
if (time <= 0) {
|
|
|
|
|
clearInterval(this.timer)
|
|
|
|
|
this.timer = null
|
|
|
|
|
uni.showToast({
|
|
|
|
|
title: '支付超时,请重新下单',
|
|
|
|
|
icon: 'none'
|
|
|
|
|
})
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
uni.navigateBack()
|
|
|
|
|
}, 1500)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
const minutes = Math.floor(time / 60)
|
|
|
|
|
const seconds = time % 60
|
|
|
|
|
this.countdown = `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`
|
|
|
|
|
}, 1000)
|
|
|
|
|
},
|
|
|
|
|
// 确认支付 debounce
|
|
|
|
|
async confirmPay() {
|
|
|
|
|
let that = this;
|
|
|
|
|
if(that.isPay) return;
|
|
|
|
|
try {
|
|
|
|
|
uni.showLoading({
|
|
|
|
|
title: '支付中...'
|
|
|
|
|
})
|
|
|
|
|
console.log(that.selectedPayment)
|
|
|
|
|
switch (that.selectedPayment) {
|
|
|
|
|
case 'wechat':
|
|
|
|
|
// 调用微信支付
|
|
|
|
|
let wechatpayfor = await request.post('/sj/wechatpayfor',that.orderInfo);
|
|
|
|
|
console.log('wechatpayfor',wechatpayfor)
|
|
|
|
|
const systemInfo = uni.getSystemInfoSync()
|
|
|
|
|
if(systemInfo.platform === 'ios') {
|
|
|
|
|
let appId = wechatpayfor.data.appid;
|
|
|
|
|
delete wechatpayfor.data.appid;
|
|
|
|
|
wechatpayfor.data['appId'] = appId;
|
|
|
|
|
console.log('wechatpayfor2',wechatpayfor)
|
|
|
|
|
}
|
|
|
|
|
console.log('================================')
|
|
|
|
|
uni.hideLoading()
|
|
|
|
|
uni.requestPayment({
|
|
|
|
|
provider: 'wxpay',
|
|
|
|
|
orderInfo: wechatpayfor.data, //微信、支付宝订单数据 【注意微信的订单信息,键值应该全部是小写,不能采用驼峰命名】
|
|
|
|
|
success: function (res) {
|
|
|
|
|
console.log('success:',res);
|
|
|
|
|
console.log(that.orderInfo.id,that.orderInfo.number)
|
|
|
|
|
// let rawdata = JSON.parse(res.rawdata);
|
|
|
|
|
request.post('/sj/wechatsearchorder',{id: that.orderInfo.id,number: that.orderInfo.number}).then(orderRes=>{
|
|
|
|
|
that.paySuccess();
|
|
|
|
|
}).catch(err=>{
|
|
|
|
|
console.log('查询状态',err)
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
fail: function (err) {
|
|
|
|
|
uni.showModal({
|
|
|
|
|
title: '提示',
|
|
|
|
|
content: '该订单未成功支付',
|
|
|
|
|
success: function (res) {
|
|
|
|
|
if (res.confirm) {
|
|
|
|
|
console.log('用户点击确定');
|
|
|
|
|
} else if (res.cancel) {
|
|
|
|
|
console.log('用户点击取消');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
console.log('fail:',JSON.stringify(err));
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
break
|
|
|
|
|
case 'alipay':
|
|
|
|
|
// 调用支付宝支付
|
|
|
|
|
let orderInfo = {...that.orderInfo};
|
|
|
|
|
orderInfo.title = that.serverTitle;
|
|
|
|
|
let alipayfor = await request.post('/sj/alipayfor',orderInfo);
|
|
|
|
|
console.log('alipayfor',alipayfor)
|
|
|
|
|
uni.hideLoading()
|
|
|
|
|
uni.requestPayment({
|
|
|
|
|
provider: 'alipay',
|
|
|
|
|
orderInfo: alipayfor.data, //微信、支付宝订单数据 【注意微信的订单信息,键值应该全部是小写,不能采用驼峰命名】
|
|
|
|
|
success: function (res) {
|
|
|
|
|
console.log('success:',res);
|
|
|
|
|
console.log('id: ',that.orderInfo.id,'number: ',that.orderInfo.number)
|
|
|
|
|
console.log('ali支付成功了====================')
|
|
|
|
|
request.post('/sj/alisearchorder',{id: that.orderInfo.id,number: that.orderInfo.number}).then(orderRes=>{
|
|
|
|
|
console.log('orderRes',orderRes,orderRes.trade_status)
|
|
|
|
|
|
|
|
|
|
console.log('ali报错了】】】】】】】】】】】】】】')
|
|
|
|
|
// if(orderRes.trade_status == 'TRADE_SUCCESS') {
|
|
|
|
|
that.paySuccess();
|
|
|
|
|
// }else {
|
|
|
|
|
// uni.showModal({
|
|
|
|
|
// title: '提示',
|
|
|
|
|
// content: '该订单未成功支付',
|
|
|
|
|
// success: function (res) {
|
|
|
|
|
// if (res.confirm) {
|
|
|
|
|
// console.log('用户点击确定');
|
|
|
|
|
// } else if (res.cancel) {
|
|
|
|
|
// console.log('用户点击取消');
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// });
|
|
|
|
|
// }
|
|
|
|
|
}).catch(err=>{
|
|
|
|
|
console.log('ali报错了】】】】】】】】】】】】】】',err)
|
|
|
|
|
console.log('查询状态',err)
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
fail: function (err) {
|
|
|
|
|
uni.showModal({
|
|
|
|
|
title: '提示',
|
|
|
|
|
content: '该订单未成功支付',
|
|
|
|
|
success: function (res) {
|
|
|
|
|
if (res.confirm) {
|
|
|
|
|
console.log('用户点击确定');
|
|
|
|
|
} else if (res.cancel) {
|
|
|
|
|
console.log('用户点击取消');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
console.log('fail:',JSON.stringify(err));
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
break
|
|
|
|
|
case 'balance':
|
|
|
|
|
// 余额支付直接成功
|
|
|
|
|
const res = await request.post('/user/balancepayfor', that.orderInfo)
|
|
|
|
|
console.log('余额支付结果',res)
|
|
|
|
|
uni.hideLoading()
|
|
|
|
|
if(res.state == 1) {
|
|
|
|
|
that.paySuccess();
|
|
|
|
|
}else if(res.state == 2) {
|
|
|
|
|
uni.showToast({
|
|
|
|
|
title: res.msg
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
uni.hideLoading()
|
|
|
|
|
console.error('支付失败:', error)
|
|
|
|
|
uni.showToast({
|
|
|
|
|
title: '支付失败,请重试',
|
|
|
|
|
icon: 'none'
|
|
|
|
|
})
|
|
|
|
|
this.isPay = false;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 支付成功
|
|
|
|
|
paySuccess() {
|
|
|
|
|
uni.showToast({
|
|
|
|
|
title: '支付成功',
|
|
|
|
|
icon: 'success'
|
|
|
|
|
})
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
uni.redirectTo({
|
|
|
|
|
url: '/pages/shop/pay-success?orderId=' + this.orderInfo.id
|
|
|
|
|
})
|
|
|
|
|
}, 50)
|
|
|
|
|
this.isPay = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style>
|
|
|
|
|
.pay-page {
|
|
|
|
|
padding-bottom: env(safe-area-inset-bottom);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 金额展示 */
|
|
|
|
|
.amount-section {
|
|
|
|
|
background-color: #FFFFFF;
|
|
|
|
|
padding: 80rpx 32rpx;
|
|
|
|
|
text-align: center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.pay_icon {
|
|
|
|
|
width: 124rpx;
|
|
|
|
|
height: 124rpx;
|
|
|
|
|
margin-bottom: 40rpx;
|
|
|
|
|
}
|
|
|
|
|
.amount {
|
|
|
|
|
margin-bottom: 24rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.symbol {
|
|
|
|
|
font-size: 28rpx;
|
2026-06-02 11:39:23 +08:00
|
|
|
color: #FF4767;
|
2026-03-24 11:45:13 +08:00
|
|
|
font-weight: 500;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.value {
|
|
|
|
|
font-size: 40rpx;
|
2026-06-02 11:39:23 +08:00
|
|
|
color: #FF4767;
|
2026-03-24 11:45:13 +08:00
|
|
|
font-weight: 700;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.countdown {
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
color: #999999;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 支付方式 */
|
|
|
|
|
.method-section {
|
|
|
|
|
background-color: #FFFFFF;
|
|
|
|
|
padding: 32rpx;
|
|
|
|
|
margin: 32rpx 24rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.section-title {
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
color: #333333;
|
|
|
|
|
margin-bottom: 32rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.balance-amount {
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
color: #999999;
|
|
|
|
|
margin-left: 16rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* 底部按钮 */
|
|
|
|
|
.footer {
|
|
|
|
|
position: fixed;
|
|
|
|
|
left: 0;
|
|
|
|
|
right: 0;
|
|
|
|
|
bottom: 0;
|
|
|
|
|
height: 150rpx;
|
|
|
|
|
background-color: #FFFFFF;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-flow: row nowrap;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
align-items: center;
|
|
|
|
|
padding: 0 24rpx;
|
|
|
|
|
padding-bottom: env(safe-area-inset-bottom);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.total-amount {
|
|
|
|
|
flex: 1;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-flow: column nowrap;
|
|
|
|
|
justify-content: flex-start;
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.total-amount .symbol {
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
font-weight: 500;
|
2026-06-02 11:39:23 +08:00
|
|
|
color: #FF4767;
|
2026-03-24 11:45:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.total-amount .amount {
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
font-weight: 500;
|
2026-06-02 11:39:23 +08:00
|
|
|
color: #FF4767;
|
2026-03-24 11:45:13 +08:00
|
|
|
}
|
|
|
|
|
.amount-lable {
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
color: #999999;
|
|
|
|
|
}
|
|
|
|
|
.pay-btn {
|
|
|
|
|
width: 492rpx;
|
|
|
|
|
height: 64rpx;
|
2026-06-02 11:39:23 +08:00
|
|
|
background: #FF4767;
|
2026-03-24 11:45:13 +08:00
|
|
|
border-radius: 32rpx;
|
|
|
|
|
color: #FFFFFF;
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.method-item {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
|
|
|
padding: 32rpx 0;
|
|
|
|
|
border-bottom: 1rpx solid rgba(0, 0, 0, 0.05);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.method-item:last-child {
|
|
|
|
|
border-bottom: none;
|
|
|
|
|
padding-bottom: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.method-info {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.method-icon {
|
|
|
|
|
width: 64rpx;
|
|
|
|
|
height: 64rpx;
|
|
|
|
|
border-radius: 32rpx;
|
|
|
|
|
margin-right: 16rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.method-name {
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
color: #333;
|
|
|
|
|
}
|
|
|
|
|
/* 多端适配 */
|
|
|
|
|
/* #ifdef H5 */
|
|
|
|
|
.footer {
|
|
|
|
|
padding-bottom: 0;
|
|
|
|
|
}
|
|
|
|
|
/* #endif */
|
|
|
|
|
</style>
|