fix: 支持关闭App后续付抖音原订单

This commit is contained in:
Codex
2026-09-09 14:39:07 +08:00
parent fe8cc21bfe
commit fd3dc6870a
3 changed files with 204 additions and 16 deletions
+56 -15
View File
@@ -52,7 +52,57 @@ function showState(state, key, orderNum) {
? '支付未成功,请查看订单' : '支付结果待确认,请稍后查看订单', icon: 'none', duration: 2500 });
}
// Runs BEFORE creating an order. Never start another payment while an earlier result is unknown.
// Called only by a user payment action, never by onShow. Renew the SAME transaction on the server.
async function continuePendingPayment(key, orderNum) {
const response = await request({ url: '/payment/douyin/resume', method: 'POST',
data: { orderNum }, isShowLoading: false });
if (key !== accountKey()) return { state: 'pending' };
if (response?.bizcode !== 100) throw new Error('暂时无法续付,请查看订单后重试');
const result = response.data;
if (!result || result.orderNum !== orderNum) throw new Error('续付订单不匹配,请查看订单');
if (result.state === 'paid' || result.state === 'closed') {
// The existing query endpoint also reconciles business orders when a webhook was missed.
const state = result.state === 'paid' ? await query(orderNum) : { state: 'failed' };
showState(state, key, orderNum);
return state;
}
if (result.state !== 'unpaid') {
const state = { state: 'pending' };
showState(state, key, orderNum);
return state;
}
if (result.payment?.orderNum !== orderNum) throw new Error('续付订单不匹配,请查看订单');
// Validate before the confirmation dialog. Never store the SDK signature locally.
toSdkPayInfo(result.payment);
const confirmed = await new Promise(resolve => uni.showModal({
title: '继续上一笔支付',
content: `上一笔抖音支付尚未完成,是否继续支付原订单?${result.payment.amount != null
? `金额:¥${result.payment.amount}。` : ''}不会创建新订单。`,
confirmText: '继续支付', cancelText: '暂不支付',
success: res => resolve(res.confirm === true), fail: () => resolve(false)
}));
if (!confirmed || key !== accountKey()) return { state: 'pending' };
return executePayment(result.payment, key);
}
async function executePayment(payment, key) {
// #ifdef APP-PLUS
if (key !== accountKey()) return { state: 'pending' };
const payInfo = toSdkPayInfo(payment);
if (!canOpenDypay()) throw new Error('请先安装或升级抖音客户端');
if (!initDypay({ appId: payInfo.appid, callbackScheme: payment.douyin.callbackScheme || 'trustbridgeapp' })) {
throw new Error('支付初始化失败,请稍后重试');
}
// Persist before entering native code so a killed process remains recoverable.
uni.setStorageSync(key, payment.orderNum);
await new Promise(resolve => openDypay({ payInfo, showLoading: true }, resolve));
const state = await query(payment.orderNum);
showState(state, key, payment.orderNum);
return state;
// #endif
}
// Runs BEFORE creating an order. A pending record offers explicit continuation, not a new order.
export async function prepareDouyinPay(payway) {
if (payway !== 'douyin') return true;
try {
@@ -66,7 +116,7 @@ export async function prepareDouyinPay(payway) {
const previous = uni.getStorageSync(key);
if (previous) {
resuming = true;
try { showState(await query(previous), key, previous); }
try { await continuePendingPayment(key, previous); }
finally { resuming = false; }
return false;
}
@@ -86,26 +136,17 @@ export async function appDypayFun(payment) {
return;
// #endif
// #ifdef APP-PLUS
if (active) return;
if (active || resuming) return;
active = true;
const key = accountKey();
try {
if (!key || !payment.orderNum) throw new Error('登录身份或支付订单编号缺失');
const payInfo = toSdkPayInfo(payment);
const previous = uni.getStorageSync(key);
if (previous) {
const state = await query(previous);
showState(state, key, previous);
if (state.state === 'pending' || previous === payment.orderNum) return state;
// Even legacy callers must not open a different payment while the saved one is unresolved.
return await continuePendingPayment(key, previous);
}
uni.setStorageSync(key, payment.orderNum);
if (!initDypay({ appId: payInfo.appid, callbackScheme: payment.douyin.callbackScheme || 'trustbridgeapp' })) {
throw new Error('支付初始化失败,请先查询订单');
}
await new Promise(resolve => openDypay({ payInfo, showLoading: true }, resolve));
const state = await query(payment.orderNum);
showState(state, key, payment.orderNum);
return state;
return await executePayment(payment, key);
} catch (error) {
if (key === accountKey()) uni.showToast({ title: error.message || '支付结果待确认,请查看订单', icon: 'none' });
return { state: 'error', message: error.message || '支付结果待确认,请查看订单' };