41 lines
1.9 KiB
JavaScript
41 lines
1.9 KiB
JavaScript
// Pure adapter: keeps merchant credentials and signing on the server.
|
|||
|
|
export function toSdkPayInfo(payment) {
|
||
|
|
const data = payment?.douyin;
|
||
|
|
if (!data) throw new Error('后端未返回抖音支付参数');
|
||
|
|
if (data.type && data.type !== 'app') throw new Error('当前仅支持抖音 App 支付');
|
||
|
|
let nested = data.orderInfo || {};
|
||
|
|
if (typeof nested === 'string') {
|
||
|
|
try { nested = JSON.parse(nested); }
|
||
|
|
catch (_) { throw new Error('抖音支付 orderInfo 格式错误'); }
|
||
|
|
}
|
||
|
|
const field = (camel, lower) => nested[lower] ?? nested[camel] ?? data[camel] ?? data[lower];
|
||
|
|
const info = {
|
||
|
|
appid: field('appId', 'appid'),
|
||
|
|
partnerid: field('mchId', 'partnerid'),
|
||
|
|
prepayid: field('prepayId', 'prepayid'),
|
||
|
|
package: field('packageValue', 'package'),
|
||
|
|
noncestr: field('nonceStr', 'noncestr'),
|
||
|
|
timestamp: field('timeStamp', 'timestamp'),
|
||
|
|
sign: field('sign', 'sign')
|
||
|
|
};
|
||
|
|
if (typeof info.timestamp === 'number' && Number.isSafeInteger(info.timestamp)) info.timestamp = String(info.timestamp);
|
||
|
|
for (const [key, value] of Object.entries(info)) {
|
||
|
|
if (typeof value !== 'string' || !value.trim()) {
|
||
|
|
throw new Error(`缺少支付参数 ${key},请先部署后端 SDK 签名补丁`);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (info.package !== 'Sign=DYPay') throw new Error('抖音支付 package 不正确');
|
||
|
|
return info;
|
||
|
|
}
|
||
|
|
|
||
|
|
// request is the App's existing authenticated request wrapper, returning ApiResult.data.
|
||
|
|
export async function queryUntilSettled(request, orderNum, { attempts = 5, pause = 1500 } = {}) {
|
||
|
|
for (let i = 0; i < attempts; i++) {
|
||
|
|
const result = await request({ url: '/payment/queryResult', method: 'GET', data: { orderNum } });
|
||
|
|
if (result?.state === 2) return { state: 'paid' };
|
||
|
|
if (result?.state === 3) return { state: 'failed' };
|
||
|
|
if (i + 1 < attempts) await new Promise(resolve => setTimeout(resolve, pause));
|
||
|
|
}
|
||
|
|
return { state: 'pending' };
|
||
|
|
}
|