feat: update payment view UI and flow
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -19,6 +19,9 @@ const isScanning = ref(false);
|
|||||||
const isSuccess = ref(false);
|
const isSuccess = ref(false);
|
||||||
let timer = null;
|
let timer = null;
|
||||||
let pollTimer = null;
|
let pollTimer = null;
|
||||||
|
let pollRetries = 0;
|
||||||
|
const MAX_POLL_RETRIES = 20;
|
||||||
|
const errorMessage = ref("");
|
||||||
|
|
||||||
const paymentMethodName = computed(() => {
|
const paymentMethodName = computed(() => {
|
||||||
return paymentMethod.value === "alipay" ? "支付宝" : "余额";
|
return paymentMethod.value === "alipay" ? "支付宝" : "余额";
|
||||||
@@ -46,33 +49,28 @@ const loadOrder = async () => {
|
|||||||
isSuccess.value = true;
|
isSuccess.value = true;
|
||||||
isScanning.value = false;
|
isScanning.value = false;
|
||||||
}
|
}
|
||||||
|
return res;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Load order failed", e);
|
console.error("Load order failed", e);
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const payOrder = async () => {
|
const payOrder = async () => {
|
||||||
try {
|
try {
|
||||||
isScanning.value = true;
|
isScanning.value = true;
|
||||||
|
errorMessage.value = "";
|
||||||
await orderApi.pay(orderId, { method: paymentMethod.value });
|
await orderApi.pay(orderId, { method: paymentMethod.value });
|
||||||
// 支付接口若未立即更新状态,将继续依赖轮询
|
// 触发一次立即刷新,后续由轮询收敛
|
||||||
|
await loadOrder();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Pay order failed", e);
|
console.error("Pay order failed", e);
|
||||||
|
errorMessage.value = "支付请求失败,请重试";
|
||||||
|
} finally {
|
||||||
isScanning.value = false;
|
isScanning.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const simulateSuccess = () => {
|
|
||||||
isScanning.value = true;
|
|
||||||
setTimeout(() => {
|
|
||||||
isScanning.value = false;
|
|
||||||
isSuccess.value = true;
|
|
||||||
setTimeout(() => {
|
|
||||||
router.replace(tenantRoute(`/me/orders/${orderId}`));
|
|
||||||
}, 1500);
|
|
||||||
}, 1000);
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
timer = setInterval(() => {
|
timer = setInterval(() => {
|
||||||
if (timeLeft.value > 0) timeLeft.value--;
|
if (timeLeft.value > 0) timeLeft.value--;
|
||||||
@@ -80,9 +78,10 @@ onMounted(() => {
|
|||||||
|
|
||||||
loadOrder();
|
loadOrder();
|
||||||
|
|
||||||
// Poll Status
|
// Poll Status (节流 + 成功即停)
|
||||||
pollTimer = setInterval(async () => {
|
pollTimer = setInterval(async () => {
|
||||||
try {
|
try {
|
||||||
|
pollRetries += 1;
|
||||||
const res = await orderApi.status(orderId);
|
const res = await orderApi.status(orderId);
|
||||||
orderStatus.value = res?.status || "";
|
orderStatus.value = res?.status || "";
|
||||||
if (res?.amount_paid !== undefined) {
|
if (res?.amount_paid !== undefined) {
|
||||||
@@ -94,14 +93,23 @@ onMounted(() => {
|
|||||||
if (orderStatus.value === "paid" || orderStatus.value === "completed") {
|
if (orderStatus.value === "paid" || orderStatus.value === "completed") {
|
||||||
isScanning.value = false;
|
isScanning.value = false;
|
||||||
isSuccess.value = true;
|
isSuccess.value = true;
|
||||||
|
errorMessage.value = "";
|
||||||
clearInterval(pollTimer);
|
clearInterval(pollTimer);
|
||||||
setTimeout(
|
setTimeout(
|
||||||
() => router.replace(tenantRoute(`/me/orders/${orderId}`)),
|
() => router.replace(tenantRoute(`/me/orders/${orderId}`)),
|
||||||
1500,
|
1200,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (pollRetries >= MAX_POLL_RETRIES && pollTimer) {
|
||||||
|
clearInterval(pollTimer);
|
||||||
|
isScanning.value = false;
|
||||||
|
errorMessage.value = "支付结果获取超时,请刷新页面或稍后重试";
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Poll status failed", e);
|
console.error("Poll status failed", e);
|
||||||
|
isScanning.value = false;
|
||||||
|
errorMessage.value = "获取支付状态失败,请重试";
|
||||||
|
if (pollTimer) clearInterval(pollTimer);
|
||||||
}
|
}
|
||||||
}, 3000);
|
}, 3000);
|
||||||
});
|
});
|
||||||
@@ -152,7 +160,11 @@ onUnmounted(() => {
|
|||||||
<div class="text-xs text-slate-400 mt-1">
|
<div class="text-xs text-slate-400 mt-1">
|
||||||
状态:{{ orderStatus || "pending" }}
|
状态:{{ orderStatus || "pending" }}
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="errorMessage" class="text-xs text-red-500 mt-2">
|
||||||
|
{{ errorMessage }}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-12">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-12">
|
||||||
<!-- Payment Methods -->
|
<!-- Payment Methods -->
|
||||||
@@ -237,19 +249,13 @@ onUnmounted(() => {
|
|||||||
<p class="text-xs text-slate-400">二维码有效时间 2小时</p>
|
<p class="text-xs text-slate-400">二维码有效时间 2小时</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Dev Tool -->
|
|
||||||
<div class="flex flex-col items-center gap-3 mt-6">
|
<div class="flex flex-col items-center gap-3 mt-6">
|
||||||
<button
|
<button
|
||||||
@click="payOrder"
|
@click="payOrder"
|
||||||
class="px-4 py-2 rounded-lg bg-primary-600 text-white hover:bg-primary-700"
|
class="px-4 py-2 rounded-lg bg-primary-600 text-white hover:bg-primary-700 disabled:opacity-60"
|
||||||
|
:disabled="isScanning || isSuccess"
|
||||||
>
|
>
|
||||||
立即支付
|
{{ isScanning ? "支付中..." : "立即支付" }}
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
@click="simulateSuccess"
|
|
||||||
class="text-xs text-slate-300 hover:text-slate-500 underline"
|
|
||||||
>
|
|
||||||
[开发调试] 模拟支付成功
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user