Plus中添加GPC模式

This commit is contained in:
QLHazyCoder
2026-05-04 18:02:00 +08:00
parent 6160f4640d
commit b595f5366a
17 changed files with 2151 additions and 64 deletions
+163 -3
View File
@@ -3,11 +3,14 @@
})(typeof self !== 'undefined' ? self : globalThis, function createGoPayUtils() {
const PLUS_PAYMENT_METHOD_PAYPAL = 'paypal';
const PLUS_PAYMENT_METHOD_GOPAY = 'gopay';
const PLUS_PAYMENT_METHOD_GPC_HELPER = 'gpc-helper';
function normalizePlusPaymentMethod(value = '') {
return String(value || '').trim().toLowerCase() === PLUS_PAYMENT_METHOD_GOPAY
? PLUS_PAYMENT_METHOD_GOPAY
: PLUS_PAYMENT_METHOD_PAYPAL;
const normalized = String(value || '').trim().toLowerCase();
if (normalized === PLUS_PAYMENT_METHOD_GPC_HELPER) {
return PLUS_PAYMENT_METHOD_GPC_HELPER;
}
return normalized === PLUS_PAYMENT_METHOD_GOPAY ? PLUS_PAYMENT_METHOD_GOPAY : PLUS_PAYMENT_METHOD_PAYPAL;
}
const DEFAULT_GOPAY_COUNTRY_CODE = '+86';
@@ -42,10 +45,167 @@
return String(value || '').trim().replace(/[^\d]/g, '');
}
function normalizeGpcHelperBaseUrl(apiUrl = '') {
let normalized = String(apiUrl || '').trim();
if (!normalized) {
return '';
}
normalized = normalized.replace(/\/+$/g, '');
normalized = normalized.replace(/\/api\/checkout\/start$/i, '');
normalized = normalized.replace(/\/api\/gopay\/(?:otp|pin)$/i, '');
normalized = normalized.replace(/\/api\/card\/balance(?:\?.*)?$/i, '');
return normalized;
}
function buildGpcHelperApiUrl(apiUrl = '', path = '') {
const baseUrl = normalizeGpcHelperBaseUrl(apiUrl);
if (!baseUrl) {
return '';
}
const normalizedPath = String(path || '').startsWith('/') ? String(path || '') : `/${String(path || '')}`;
return `${baseUrl}${normalizedPath}`;
}
function buildGpcCardBalanceUrl(apiUrl = '', cardKey = '') {
const endpoint = buildGpcHelperApiUrl(apiUrl, '/api/card/balance');
if (!endpoint) {
return '';
}
return `${endpoint}?card_key=${encodeURIComponent(String(cardKey || '').trim())}`;
}
function extractGpcResponseErrorDetail(payload = {}, status = 0) {
if (!payload || typeof payload !== 'object') {
return status ? `HTTP ${status}` : '未知错误';
}
const payloadText = JSON.stringify(payload).toLowerCase();
if (/account\s+already\s+linked/i.test(payloadText)) {
return 'GOPAY已经绑了订阅,需要手动解绑';
}
const direct = payload.detail
?? payload.message
?? payload.error
?? payload.error_description
?? payload.reason;
if (direct !== undefined && direct !== null && String(direct).trim()) {
const directText = String(direct).trim();
return /account\s+already\s+linked/i.test(directText)
? 'GOPAY已经绑了订阅,需要手动解绑'
: directText;
}
const errorMessages = payload.error_messages ?? payload.errorMessages;
if (Array.isArray(errorMessages) && errorMessages.length > 0) {
const firstMessage = String(errorMessages[0] || '').trim();
if (/account\s+already\s+linked/i.test(firstMessage)) {
return 'GOPAY已经绑了订阅,需要手动解绑';
}
if (firstMessage) {
return firstMessage;
}
}
const errors = payload.errors;
if (Array.isArray(errors) && errors.length > 0) {
const first = errors[0];
if (typeof first === 'string') {
return first.trim() || (status ? `HTTP ${status}` : '未知错误');
}
if (first && typeof first === 'object') {
const field = Array.isArray(first.loc) ? first.loc.join('.') : String(first.field || first.path || '').trim();
const message = String(first.msg || first.message || first.error || '').trim();
return [field, message].filter(Boolean).join(': ') || JSON.stringify(first);
}
}
return status ? `HTTP ${status}` : '未知错误';
}
function buildGpcOtpPayload(input = {}) {
const payload = {
reference_id: String(input.reference_id ?? input.referenceId ?? '').trim(),
otp: normalizeGoPayOtp(input.otp ?? input.code ?? ''),
card_key: String(input.card_key ?? input.cardKey ?? '').trim(),
};
const flowId = String(input.flow_id ?? input.flowId ?? '').trim();
const gopayGuid = String(input.gopay_guid ?? input.gopayGuid ?? '').trim();
const redirectUrl = String(input.redirect_url ?? input.redirectUrl ?? '').trim();
if (flowId) payload.flow_id = flowId;
if (gopayGuid) payload.gopay_guid = gopayGuid;
if (redirectUrl) payload.redirect_url = redirectUrl;
return payload;
}
function buildGpcOtpRetryPayload(input = {}) {
const payload = buildGpcOtpPayload(input);
return { ...payload, code: payload.otp };
}
function buildGpcPinPayload(input = {}) {
const payload = {
reference_id: String(input.reference_id ?? input.referenceId ?? '').trim(),
challenge_id: String(input.challenge_id ?? input.challengeId ?? '').trim(),
gopay_guid: String(input.gopay_guid ?? input.gopayGuid ?? '').trim(),
pin: normalizeGoPayPin(input.pin ?? ''),
card_key: String(input.card_key ?? input.cardKey ?? '').trim(),
};
const flowId = String(input.flow_id ?? input.flowId ?? '').trim();
const redirectUrl = String(input.redirect_url ?? input.redirectUrl ?? '').trim();
if (flowId) payload.flow_id = flowId;
if (redirectUrl) payload.redirect_url = redirectUrl;
return payload;
}
function buildGpcPinRetryPayload(input = {}) {
const payload = buildGpcPinPayload(input);
return { ...payload, challengeId: payload.challenge_id };
}
function formatGpcBalancePayload(payload = {}) {
if (!payload || typeof payload !== 'object') {
return '';
}
const candidates = [
payload.remaining_uses,
payload.remainingUses,
payload.balance,
payload.remaining,
payload.uses,
payload.available_uses,
payload.availableUses,
];
const firstValue = candidates.find((value) => value !== undefined && value !== null && String(value).trim() !== '');
const status = String(payload.card_status || payload.cardStatus || payload.status || '').trim();
const flowId = String(payload.flow_id || payload.flowId || '').trim();
const parts = [];
if (firstValue !== undefined) {
parts.push(`余额 ${firstValue}`);
}
if (status) {
parts.push(`状态 ${status}`);
}
if (flowId) {
parts.push(`flow_id ${flowId}`);
}
return parts.join('');
}
return {
DEFAULT_GOPAY_COUNTRY_CODE,
PLUS_PAYMENT_METHOD_GPC_HELPER,
PLUS_PAYMENT_METHOD_GOPAY,
PLUS_PAYMENT_METHOD_PAYPAL,
buildGpcCardBalanceUrl,
buildGpcHelperApiUrl,
buildGpcOtpPayload,
buildGpcOtpRetryPayload,
buildGpcPinPayload,
buildGpcPinRetryPayload,
extractGpcResponseErrorDetail,
formatGpcBalancePayload,
normalizeGpcHelperBaseUrl,
normalizeGoPayCountryCode,
normalizeGoPayPhone,
normalizeGoPayPhoneForCountry,