Lufaneng 10 months ago
parent 2a0fa0836d
commit af9c4a4e5b

@ -107,6 +107,13 @@
{ {
"navigationBarTitleText" : "确认支付" "navigationBarTitleText" : "确认支付"
} }
},
{
"path" : "payment-result/payment-result",
"style" :
{
"navigationBarTitleText" : "支付结果"
}
} }
] ]
} }

@ -0,0 +1,393 @@
<template>
<view class="container">
<!-- 支付结果显示 -->
<view class="result-section">
<!-- 加载中状态 -->
<view v-if="paymentStatus === 'loading'" class="status-loading">
<view class="loading-icon">
<uv-loading-icon mode="circle" color="#4285f4" size="60"></uv-loading-icon>
</view>
<view class="status-title">支付处理中...</view>
<view class="status-desc">请稍候正在确认支付结果</view>
<view class="countdown-text">{{ countdownText }}</view>
</view>
<!-- 支付成功 -->
<view v-else-if="paymentStatus === 'success'" class="status-success">
<view class="success-icon">
<uv-icon name="checkmark-circle-fill" color="#52c41a" size="80"></uv-icon>
</view>
<view class="status-title">支付成功</view>
<view class="status-desc">恭喜您会员服务已开通</view>
</view>
<!-- 支付失败 -->
<view v-else-if="paymentStatus === 'failed'" class="status-failed">
<view class="failed-icon">
<uv-icon name="close-circle-fill" color="#ff4d4f" size="80"></uv-icon>
</view>
<view class="status-title">支付失败</view>
<view class="status-desc">{{ failedReason || '支付过程中出现问题,请重试' }}</view>
</view>
<!-- 支付取消 -->
<view v-else-if="paymentStatus === 'cancelled'" class="status-cancelled">
<view class="cancelled-icon">
<uv-icon name="info-circle-fill" color="#faad14" size="80"></uv-icon>
</view>
<view class="status-title">支付已取消</view>
<view class="status-desc">您已取消本次支付</view>
</view>
<!-- 超时状态 -->
<view v-else-if="paymentStatus === 'timeout'" class="status-timeout">
<view class="timeout-icon">
<uv-icon name="clock-fill" color="#faad14" size="80"></uv-icon>
</view>
<view class="status-title">查询超时</view>
<view class="status-desc">支付结果查询超时请手动查看订单状态</view>
</view>
</view>
<!-- 订单信息 -->
<view class="order-info" v-if="orderInfo">
<view class="info-title">订单信息</view>
<view class="info-item">
<text class="label">订单号</text>
<text class="value">{{ orderNo }}</text>
</view>
<view class="info-item" v-if="orderInfo.plan_name">
<text class="label">商品</text>
<text class="value">{{ orderInfo.plan_name }}</text>
</view>
<view class="info-item" v-if="orderInfo.amount">
<text class="label">金额</text>
<text class="value price">¥{{ orderInfo.amount }}</text>
</view>
<view class="info-item" v-if="orderInfo.pay_time">
<text class="label">支付时间</text>
<text class="value">{{ formatTime(orderInfo.pay_time) }}</text>
</view>
</view>
<!-- 底部按钮 -->
<view class="bottom-section">
<view class="button-group">
<!-- 支付成功时的按钮 -->
<template v-if="paymentStatus === 'success'">
<uv-button type="primary" @click="goToMine">
返回会员中心
</uv-button>
</template>
<!-- 支付失败时的按钮 -->
<template v-else-if="paymentStatus === 'failed'">
<uv-button type="primary" @click="goToMine" customStyle="margin-right: 12px; flex: 1;">
返回会员中心
</uv-button>
<!-- <uv-button type="primary" @click="retryPayment" customStyle="flex: 1;">
重新支付
</uv-button> -->
</template>
<!-- 其他状态的按钮 -->
<template v-else>
<uv-button type="primary" plain @click="goToMine">
返回会员中心
</uv-button>
<uv-button type="primary" @click="checkOrderStatus" >
查看订单
</uv-button>
</template>
</view>
</view>
</view>
</template>
<script setup>
import {
ref,
onMounted,
onUnmounted
} from "vue";
import {
onLoad
} from "@dcloudio/uni-app";
import {
useUserStore
} from "@/store";
import RPC from "@/utils/request";
import dayjs from "dayjs";
const userStore = useUserStore();
//
const orderNo = ref('');
//
const paymentStatus = ref('loading'); // loading, success, failed, cancelled, timeout
const failedReason = ref('');
const orderInfo = ref(null);
const countdown = ref(60); // 60
const countdownText = ref('');
//
let queryTimer = null;
let countdownTimer = null;
//
onLoad((options) => {
orderNo.value = options.order_no || '';
if (orderNo.value) {
startQueryPaymentStatus();
} else {
paymentStatus.value = 'failed';
failedReason.value = '订单号参数缺失';
}
});
//
const startQueryPaymentStatus = () => {
//
startCountdown();
//
queryPaymentStatus();
// 3
queryTimer = setInterval(() => {
queryPaymentStatus();
}, 3000);
};
//
const queryPaymentStatus = async () => {
try {
const res = await RPC.post('/membership/order/status', {
order_no: orderNo.value
});
orderInfo.value = res;
//
if (res.status === 'paid') {
paymentStatus.value = 'success';
clearTimers();
} else if (res.status === 'failed') {
paymentStatus.value = 'failed';
failedReason.value = res.fail_reason || '支付失败';
clearTimers();
} else if (res.status === 'canceled' || res.status === 'cancelled') {
paymentStatus.value = 'cancelled';
clearTimers();
} else if (res.status === 'created' || res.status === 'pending') {
//
paymentStatus.value = 'loading';
}
} catch (error) {
console.error('查询支付状态失败:', error);
//
if (countdown.value <= 0) {
paymentStatus.value = 'timeout';
clearTimers();
}
}
};
//
const startCountdown = () => {
updateCountdownText();
countdownTimer = setInterval(() => {
countdown.value--;
updateCountdownText();
if (countdown.value <= 0) {
paymentStatus.value = 'timeout';
clearTimers();
}
}, 1000);
};
//
const updateCountdownText = () => {
countdownText.value = `查询超时倒计时:${countdown.value}`;
};
//
const clearTimers = () => {
if (queryTimer) {
clearInterval(queryTimer);
queryTimer = null;
}
if (countdownTimer) {
clearInterval(countdownTimer);
countdownTimer = null;
}
};
//
const formatTime = (timestamp) => {
if (!timestamp) return '';
return dayjs(timestamp * 1000).format('YYYY-MM-DD HH:mm:ss');
};
//
const goToMine = () => {
uni.switchTab({
url: '/pages/mine/mine'
});
};
//
const retryPayment = () => {
//
uni.navigateBack({
delta: 1
});
};
//
const checkOrderStatus = () => {
uni.switchTab({
url: '/pages/order/order'
});
};
//
onUnmounted(() => {
clearTimers();
});
</script>
<style lang="scss" scoped>
.container {
font-size: 14px;
background-color: #f8f8f8;
min-height: 100vh;
padding: 20px 16px;
box-sizing: border-box;
}
.result-section {
background: white;
border-radius: 12px;
padding: 40px 20px;
text-align: center;
margin-bottom: 20px;
.loading-icon,
.success-icon,
.failed-icon,
.cancelled-icon,
.timeout-icon {
margin-bottom: 20px;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
}
.status-title {
font-size: 20px;
font-weight: bold;
color: #333;
margin-bottom: 8px;
}
.status-desc {
font-size: 14px;
color: #666;
margin-bottom: 16px;
}
.countdown-text {
font-size: 12px;
color: #999;
}
.status-success {
.status-title {
color: #52c41a;
}
}
.status-failed {
.status-title {
color: #ff4d4f;
}
}
.status-cancelled {
.status-title {
color: #faad14;
}
}
.status-timeout {
.status-title {
color: #faad14;
}
}
}
.order-info {
background: white;
border-radius: 12px;
padding: 16px;
margin-bottom: 20px;
.info-title {
font-size: 16px;
font-weight: 500;
color: #333;
margin-bottom: 16px;
}
.info-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
border-bottom: 1px solid #f0f0f0;
&:last-child {
border-bottom: none;
}
.label {
font-size: 14px;
color: #666;
}
.value {
font-size: 14px;
color: #333;
&.price {
color: #ff3333;
font-weight: 500;
}
}
}
}
.bottom-section {
// position: fixed;
// bottom: 0;
// left: 0;
// right: 0;
background: white;
padding: 16px;
border-radius: 10px;
// border-top: 1px solid #e5e5e5;
/* #ifdef H5 */
// bottom: 50px;
/* H5环境下给tabBar留出空间 */
/* #endif */
.button-group {
display: flex;
gap: 30px;
}
}
</style>

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save