优化
This commit is contained in:
Submodule libs/rnwalletman updated: f4bdf90948...732f4c90f3
File diff suppressed because it is too large
Load Diff
Submodule servers/walletman updated: 4ba972771c...e5299b7665
704
upi.html
704
upi.html
@@ -1,353 +1,399 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>UPI Pay Test</title>
|
<title>UPI Pay Test</title>
|
||||||
<style>
|
<style>
|
||||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
* {
|
||||||
body {
|
box-sizing: border-box;
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
margin: 0;
|
||||||
background: #f0f2f5;
|
padding: 0;
|
||||||
min-height: 100vh;
|
}
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
body {
|
||||||
align-items: center;
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||||
padding: 32px 16px;
|
background: #f0f2f5;
|
||||||
gap: 20px;
|
min-height: 100vh;
|
||||||
}
|
display: flex;
|
||||||
h2 { color: #1a1a2e; font-size: 20px; }
|
flex-direction: column;
|
||||||
.card {
|
align-items: center;
|
||||||
background: #fff;
|
padding: 32px 16px;
|
||||||
border-radius: 16px;
|
gap: 20px;
|
||||||
padding: 20px;
|
}
|
||||||
width: 100%;
|
|
||||||
max-width: 380px;
|
h2 {
|
||||||
box-shadow: 0 4px 12px rgba(0,0,0,.08);
|
color: #1a1a2e;
|
||||||
display: flex;
|
font-size: 20px;
|
||||||
flex-direction: column;
|
}
|
||||||
gap: 14px;
|
|
||||||
}
|
.card {
|
||||||
label { font-size: 13px; color: #888; display: block; margin-bottom: 6px; }
|
background: #fff;
|
||||||
input, select {
|
border-radius: 16px;
|
||||||
border: 1.5px solid #e0e0e0;
|
padding: 20px;
|
||||||
border-radius: 10px;
|
width: 100%;
|
||||||
padding: 10px 14px;
|
max-width: 380px;
|
||||||
font-size: 15px;
|
box-shadow: 0 4px 12px rgba(0, 0, 0, .08);
|
||||||
width: 100%;
|
display: flex;
|
||||||
outline: none;
|
flex-direction: column;
|
||||||
background: #fafafa;
|
gap: 14px;
|
||||||
appearance: none;
|
}
|
||||||
}
|
|
||||||
input:focus, select:focus { border-color: #5f259f; }
|
label {
|
||||||
.badge {
|
font-size: 13px;
|
||||||
display: inline-block;
|
color: #888;
|
||||||
font-size: 10px;
|
display: block;
|
||||||
padding: 2px 7px;
|
margin-bottom: 6px;
|
||||||
border-radius: 20px;
|
}
|
||||||
font-weight: 600;
|
|
||||||
margin-left: 6px;
|
input,
|
||||||
vertical-align: middle;
|
select {
|
||||||
}
|
border: 1.5px solid #e0e0e0;
|
||||||
.badge-biz { background: #e8f5e9; color: #2e7d32; }
|
border-radius: 10px;
|
||||||
.badge-pers { background: #e3f2fd; color: #1565c0; }
|
padding: 10px 14px;
|
||||||
.link-box {
|
font-size: 15px;
|
||||||
background: #f5f0ff;
|
width: 100%;
|
||||||
border-radius: 10px;
|
outline: none;
|
||||||
padding: 12px;
|
background: #fafafa;
|
||||||
font-size: 11px;
|
appearance: none;
|
||||||
color: #5f259f;
|
}
|
||||||
word-break: break-all;
|
|
||||||
line-height: 1.7;
|
input:focus,
|
||||||
min-height: 44px;
|
select:focus {
|
||||||
}
|
border-color: #5f259f;
|
||||||
.warn-box {
|
}
|
||||||
background: #fff3e0;
|
|
||||||
border-radius: 10px;
|
.badge {
|
||||||
padding: 10px 12px;
|
display: inline-block;
|
||||||
font-size: 12px;
|
font-size: 10px;
|
||||||
color: #e65100;
|
padding: 2px 7px;
|
||||||
display: none;
|
border-radius: 20px;
|
||||||
}
|
font-weight: 600;
|
||||||
.pay-btn {
|
margin-left: 6px;
|
||||||
display: block;
|
vertical-align: middle;
|
||||||
width: 100%;
|
}
|
||||||
padding: 14px;
|
|
||||||
border: none;
|
.badge-biz {
|
||||||
border-radius: 12px;
|
background: #e8f5e9;
|
||||||
font-size: 16px;
|
color: #2e7d32;
|
||||||
font-weight: 700;
|
}
|
||||||
color: #fff;
|
|
||||||
cursor: pointer;
|
.badge-pers {
|
||||||
text-align: center;
|
background: #e3f2fd;
|
||||||
text-decoration: none;
|
color: #1565c0;
|
||||||
transition: opacity .15s, transform .1s;
|
}
|
||||||
}
|
|
||||||
.pay-btn:active { opacity: .85; transform: scale(.98); }
|
.link-box {
|
||||||
.c-paytm { background: linear-gradient(135deg, #002970, #00baf2); }
|
background: #f5f0ff;
|
||||||
.c-phonepe { background: linear-gradient(135deg, #5f259f, #7b3fc4); }
|
border-radius: 10px;
|
||||||
.c-mobikwik { background: linear-gradient(135deg, #1565c0, #42a5f5); }
|
padding: 12px;
|
||||||
.c-freecharge { background: linear-gradient(135deg, #00897b, #4db6ac); }
|
font-size: 11px;
|
||||||
.c-upi { background: linear-gradient(135deg, #37474f, #78909c); }
|
color: #5f259f;
|
||||||
.qr-wrap { text-align: center; }
|
word-break: break-all;
|
||||||
.qr-wrap p { font-size: 13px; color: #888; margin-bottom: 10px; }
|
line-height: 1.7;
|
||||||
#qrcode {
|
min-height: 44px;
|
||||||
display: inline-block;
|
}
|
||||||
background: #fff;
|
|
||||||
padding: 12px;
|
.warn-box {
|
||||||
border-radius: 12px;
|
background: #fff3e0;
|
||||||
box-shadow: 0 4px 12px rgba(0,0,0,.1);
|
border-radius: 10px;
|
||||||
}
|
padding: 10px 12px;
|
||||||
</style>
|
font-size: 12px;
|
||||||
|
color: #e65100;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pay-btn {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
padding: 14px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 12px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: opacity .15s, transform .1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pay-btn:active {
|
||||||
|
opacity: .85;
|
||||||
|
transform: scale(.98);
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-paytm {
|
||||||
|
background: linear-gradient(135deg, #002970, #00baf2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-phonepe {
|
||||||
|
background: linear-gradient(135deg, #5f259f, #7b3fc4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-mobikwik {
|
||||||
|
background: linear-gradient(135deg, #1565c0, #42a5f5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-freecharge {
|
||||||
|
background: linear-gradient(135deg, #00897b, #4db6ac);
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-upi {
|
||||||
|
background: linear-gradient(135deg, #37474f, #78909c);
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-wrap {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-wrap p {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #888;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qrcode {
|
||||||
|
display: inline-block;
|
||||||
|
background: #fff;
|
||||||
|
padding: 12px;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, .1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<h2>UPI Pay Test</h2>
|
<h2>UPI Pay Test</h2>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div>
|
<div>
|
||||||
<label>Wallet</label>
|
<label>Wallet</label>
|
||||||
<select id="wallet">
|
<select id="wallet">
|
||||||
<optgroup label="── Business ──">
|
<optgroup label="── Business ──">
|
||||||
<option value="gpay_biz">Google Pay Business</option>
|
<option value="gpay_biz">Google Pay Business</option>
|
||||||
<option value="paytm_biz">Paytm Business</option>
|
<option value="paytm_biz">Paytm Business</option>
|
||||||
<option value="phonepe_biz">PhonePe Business</option>
|
<option value="phonepe_biz">PhonePe Business</option>
|
||||||
<option value="bharatpe_biz">BharatPe Business</option>
|
<option value="bharatpe_biz">BharatPe Business</option>
|
||||||
</optgroup>
|
</optgroup>
|
||||||
<optgroup label="── Personal ──">
|
<optgroup label="── Personal ──">
|
||||||
<option value="paytm_per">Paytm Personal</option>
|
<option value="paytm_per">Paytm Personal</option>
|
||||||
<option value="phonepe_per">PhonePe Personal</option>
|
<option value="phonepe_per">PhonePe Personal</option>
|
||||||
<option value="mobikwik_per">MobiKwik Personal</option>
|
<option value="mobikwik_per">MobiKwik Personal</option>
|
||||||
<option value="freecharge_per">Freecharge Personal</option>
|
<option value="freecharge_per">Freecharge Personal</option>
|
||||||
</optgroup>
|
</optgroup>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label>Payment App</label>
|
<label>Payment App</label>
|
||||||
<select id="app">
|
<select id="app">
|
||||||
<option value="paytm">Paytm</option>
|
<option value="paytm">Paytm</option>
|
||||||
<option value="phonepe">PhonePe (native p2p)</option>
|
<option value="phonepe">PhonePe (native p2p)</option>
|
||||||
<option value="phonepe_pay">PhonePe (pay)</option>
|
<option value="phonepe_pay">PhonePe (pay)</option>
|
||||||
<option value="mobikwik">MobiKwik</option>
|
<option value="mobikwik">MobiKwik</option>
|
||||||
<option value="freecharge">Freecharge</option>
|
<option value="freecharge">Freecharge</option>
|
||||||
<option value="upi">Other UPI</option>
|
<option value="upi">Other UPI</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label>Amount ₹</label>
|
<label>Amount ₹</label>
|
||||||
<input id="amount" type="number" value="51" min="50" step="1">
|
<input id="amount" type="number" value="51" min="50" step="1">
|
||||||
</div>
|
</div>
|
||||||
<div style="background:#f9f9f9;border-radius:10px;padding:12px;display:flex;flex-direction:column;gap:6px;">
|
<div style="background:#f9f9f9;border-radius:10px;padding:12px;display:flex;flex-direction:column;gap:6px;">
|
||||||
<div style="display:flex;justify-content:space-between;font-size:13px;">
|
<div style="display:flex;justify-content:space-between;font-size:13px;">
|
||||||
<span style="color:#888;">Receiver (Payee)</span>
|
<span style="color:#888;">Receiver (Payee)</span>
|
||||||
<span id="info-pn" style="font-weight:600;color:#1a1a2e;text-align:right;max-width:60%;"></span>
|
<span id="info-pn" style="font-weight:600;color:#1a1a2e;text-align:right;max-width:60%;"></span>
|
||||||
|
</div>
|
||||||
|
<div style="display:flex;justify-content:space-between;font-size:13px;">
|
||||||
|
<span style="color:#888;">UPI ID</span>
|
||||||
|
<span id="info-pa"
|
||||||
|
style="font-weight:600;color:#5f259f;font-size:12px;text-align:right;max-width:60%;word-break:break-all;"></span>
|
||||||
|
</div>
|
||||||
|
<div style="display:flex;justify-content:space-between;font-size:13px;">
|
||||||
|
<span style="color:#888;">Amount</span>
|
||||||
|
<span id="info-am" style="font-weight:600;color:#1a1a2e;"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="warn-box" class="warn-box"></div>
|
||||||
|
<div>
|
||||||
|
<label>Deep Link</label>
|
||||||
|
<div class="link-box" id="link-display"></div>
|
||||||
|
</div>
|
||||||
|
<a class="pay-btn c-paytm" id="pay-btn" href="#">Pay Now</a>
|
||||||
</div>
|
</div>
|
||||||
<div style="display:flex;justify-content:space-between;font-size:13px;">
|
|
||||||
<span style="color:#888;">UPI ID</span>
|
<div class="qr-wrap">
|
||||||
<span id="info-pa" style="font-weight:600;color:#5f259f;font-size:12px;text-align:right;max-width:60%;word-break:break-all;"></span>
|
<p>UPI QR</p>
|
||||||
|
<div id="qrcode"></div>
|
||||||
</div>
|
</div>
|
||||||
<div style="display:flex;justify-content:space-between;font-size:13px;">
|
|
||||||
<span style="color:#888;">Amount</span>
|
|
||||||
<span id="info-am" style="font-weight:600;color:#1a1a2e;"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="warn-box" class="warn-box"></div>
|
|
||||||
<div>
|
|
||||||
<label>Deep Link</label>
|
|
||||||
<div class="link-box" id="link-display"></div>
|
|
||||||
</div>
|
|
||||||
<a class="pay-btn c-paytm" id="pay-btn" href="#">Pay Now</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="qr-wrap">
|
<script src="https://cdn.jsdelivr.net/npm/qrcodejs/qrcode.min.js"></script>
|
||||||
<p>UPI QR</p>
|
<script>
|
||||||
<div id="qrcode"></div>
|
const WALLETS = {
|
||||||
</div>
|
gpay_biz: {
|
||||||
|
label: 'Google Pay Business',
|
||||||
|
pa: '7528905079@okbizaxis', pn: 'Kularenterprises',
|
||||||
|
extra: (p) => `&tr=BCR2DN4TXXWO5PRF&tn=tH0yMnoPPH`,
|
||||||
|
warn: null,
|
||||||
|
},
|
||||||
|
paytm_biz: {
|
||||||
|
label: 'Paytm Business',
|
||||||
|
pa: 'paytm.s20dk3t@pty', pn: 'Paytm',
|
||||||
|
extra: () => '',
|
||||||
|
warn: null,
|
||||||
|
},
|
||||||
|
phonepe_biz: {
|
||||||
|
label: 'PhonePe Business',
|
||||||
|
pa: 'Q465518940@ybl', pn: 'PhonePeMerchant',
|
||||||
|
extra: () => '&mc=0000&mode=02&purpose=00',
|
||||||
|
warn: 'QR-only merchant — link payment may be rejected. Scan QR instead.',
|
||||||
|
},
|
||||||
|
bharatpe_biz: {
|
||||||
|
label: 'BharatPe Business',
|
||||||
|
pa: 'BHARATPE.8A0T1R2O5E77327@fbpe', pn: 'BharatPe Merchant',
|
||||||
|
extra: () => '&tn=Pay%20To%20BharatPe%20Merchant',
|
||||||
|
warn: null,
|
||||||
|
},
|
||||||
|
paytm_per: {
|
||||||
|
label: 'Paytm Personal',
|
||||||
|
pa: 'optimism2@ptyes', pn: 'Gurvir Singh',
|
||||||
|
extra: () => '',
|
||||||
|
warn: null,
|
||||||
|
},
|
||||||
|
phonepe_per: {
|
||||||
|
label: 'PhonePe Personal',
|
||||||
|
pa: '7528905079@ybl', pn: 'Gurvir Singh',
|
||||||
|
extra: () => '',
|
||||||
|
warn: null,
|
||||||
|
},
|
||||||
|
mobikwik_per: {
|
||||||
|
label: 'MobiKwik Personal',
|
||||||
|
pa: '7528905079-1@ikwik', pn: 'Gurvir Singh',
|
||||||
|
extra: () => '',
|
||||||
|
warn: null,
|
||||||
|
},
|
||||||
|
freecharge_per: {
|
||||||
|
label: 'Freecharge Personal',
|
||||||
|
pa: 'simple6812@freecharge', pn: 'Gurvir Singh',
|
||||||
|
extra: () => '',
|
||||||
|
warn: null,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/qrcodejs/qrcode.min.js"></script>
|
function phonepeNative(pa, pn, am, note) {
|
||||||
<script>
|
const payload = {
|
||||||
const WALLETS = {
|
contact: { cbsName: '', nickName: pn, vpa: pa, type: 'VPA' },
|
||||||
gpay_biz: {
|
p2pPaymentCheckoutParams: {
|
||||||
label: 'Google Pay Business',
|
note: note || 'payment',
|
||||||
pa: '7528905079@okbizaxis', pn: 'Kularenterprises',
|
isByDefaultKnownContact: true,
|
||||||
extra: (p) => `&tr=BCR2DN4TXXWO5PRF&tn=tH0yMnoPPH`,
|
enableSpeechToText: false,
|
||||||
warn: null,
|
allowAmountEdit: false,
|
||||||
},
|
showQrCodeOption: false,
|
||||||
paytm_biz: {
|
disableViewHistory: true,
|
||||||
label: 'Paytm Business',
|
shouldShowUnsavedContactBanner: false,
|
||||||
pa: 'paytm.s20dk3t@pty', pn: 'Paytm',
|
isRecurring: false,
|
||||||
extra: () => '',
|
checkoutType: 'DEFAULT',
|
||||||
warn: null,
|
transactionContext: 'p2p',
|
||||||
},
|
initialAmount: Math.round(parseFloat(am) * 100), // paise
|
||||||
phonepe_biz: {
|
disableNotesEdit: true,
|
||||||
label: 'PhonePe Business',
|
showKeyboard: true,
|
||||||
pa: 'Q465518940@ybl', pn: 'PhonePeMerchant',
|
currency: 'INR',
|
||||||
extra: () => '&mc=0000&mode=02&purpose=00',
|
shouldShowMaskedNumber: true,
|
||||||
warn: 'QR-only merchant — link payment may be rejected. Scan QR instead.',
|
},
|
||||||
},
|
};
|
||||||
bharatpe_biz: {
|
return `phonepe://native?data=${encodeURIComponent(btoa(JSON.stringify(payload)))}&id=p2ppayment`;
|
||||||
label: 'BharatPe Business',
|
}
|
||||||
pa: 'BHARATPE.8A0T1R2O5E77327@fbpe', pn: 'BharatPe Merchant',
|
|
||||||
extra: () => '&tn=Pay%20To%20BharatPe%20Merchant',
|
|
||||||
warn: null,
|
|
||||||
},
|
|
||||||
paytm_per: {
|
|
||||||
label: 'Paytm Personal',
|
|
||||||
pa: 'optimism2@ptyes', pn: 'Gurvir Singh',
|
|
||||||
extra: () => '',
|
|
||||||
warn: null,
|
|
||||||
},
|
|
||||||
phonepe_per: {
|
|
||||||
label: 'PhonePe Personal',
|
|
||||||
pa: '7528905079@ybl', pn: 'Gurvir Singh',
|
|
||||||
extra: () => '',
|
|
||||||
warn: null,
|
|
||||||
},
|
|
||||||
mobikwik_per: {
|
|
||||||
label: 'MobiKwik Personal',
|
|
||||||
pa: '7528905079-1@ikwik', pn: 'Gurvir Singh',
|
|
||||||
extra: () => '',
|
|
||||||
warn: null,
|
|
||||||
},
|
|
||||||
freecharge_per: {
|
|
||||||
label: 'Freecharge Personal',
|
|
||||||
pa: 'simple6812@freecharge', pn: 'Gurvir Singh',
|
|
||||||
extra: () => '',
|
|
||||||
warn: null,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
function phonepeNative(pa, pn, am, note) {
|
const APP_SCHEMES = {
|
||||||
const payload = {
|
paytm: (pa, pn, am, extra) => `paytmmp://cash_wallet?featuretype=money_transfer&pa=${pa}&pn=${pn}&am=${am}&cu=INR&mc=0000&mode=02&purpose=00&orgid=159002${extra}`,
|
||||||
contact: { cbsName: '', nickName: pn, vpa: pa, type: 'VPA' },
|
phonepe: (pa, pn, am) => phonepeNative(pa, pn, am, 'payment'),
|
||||||
p2pPaymentCheckoutParams: {
|
phonepe_pay: (pa, pn, am, extra) => `phonepe://pay?pa=${pa}&pn=${pn}&am=${am}&cu=INR${extra}`,
|
||||||
note: note || 'payment',
|
mobikwik: (pa, pn, am, extra) => { const tn = (extra.match(/[?&]tn=([^&]*)/) || [])[1] || 'payment'; return `mobikwik://moneytransfer/upi/verifyVpa?vpa=${encodeURIComponent(pa)}&amount=${am}¬e=${tn}`; },
|
||||||
isByDefaultKnownContact: true,
|
freecharge: (pa, pn, am, extra) => `freechargeupi://pay?pa=${pa}&pn=${pn}&am=${am}&cu=INR${extra}`,
|
||||||
enableSpeechToText: false,
|
// fallback 在 scheduleAutoClick 里处理
|
||||||
allowAmountEdit: false,
|
upi: (pa, pn, am, extra) => `upi://pay?pa=${pa}&pn=${pn}&am=${am}&cu=INR${extra}`,
|
||||||
showQrCodeOption: false,
|
};
|
||||||
disableViewHistory: true,
|
|
||||||
shouldShowUnsavedContactBanner: false,
|
|
||||||
isRecurring: false,
|
|
||||||
checkoutType: 'DEFAULT',
|
|
||||||
transactionContext: 'p2p',
|
|
||||||
initialAmount: Math.round(parseFloat(am) * 100), // paise
|
|
||||||
disableNotesEdit: true,
|
|
||||||
showKeyboard: true,
|
|
||||||
currency: 'INR',
|
|
||||||
shouldShowMaskedNumber: true,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
return `phonepe://native?data=${encodeURIComponent(btoa(JSON.stringify(payload)))}&id=p2ppayment`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const APP_SCHEMES = {
|
const APP_COLORS = {
|
||||||
paytm: (pa, pn, am, extra) => `paytmmp://cash_wallet?featuretype=money_transfer&pa=${pa}&pn=${pn}&am=${am}&cu=INR&mc=0000&mode=02&purpose=00&orgid=159002${extra}`,
|
paytm: 'c-paytm', phonepe: 'c-phonepe', phonepe_pay: 'c-phonepe',
|
||||||
phonepe: (pa, pn, am) => phonepeNative(pa, pn, am, 'payment'),
|
mobikwik: 'c-mobikwik', freecharge: 'c-freecharge', upi: 'c-upi',
|
||||||
phonepe_pay: (pa, pn, am, extra) => `phonepe://pay?pa=${pa}&pn=${pn}&am=${am}&cu=INR${extra}`,
|
};
|
||||||
mobikwik: (pa, pn, am, extra) => { const tn = (extra.match(/[?&]tn=([^&]*)/) || [])[1] || 'payment'; return `mobikwik://moneytransfer/upi/verifyVpa?vpa=${encodeURIComponent(pa)}&amount=${am}¬e=${tn}`; },
|
|
||||||
freecharge: (pa, pn, am, extra) => `freechargeupi://pay?pa=${pa}&pn=${pn}&am=${am}&cu=INR${extra}`,
|
|
||||||
// fallback 在 scheduleAutoClick 里处理
|
|
||||||
upi: (pa, pn, am, extra) => `upi://pay?pa=${pa}&pn=${pn}&am=${am}&cu=INR${extra}`,
|
|
||||||
};
|
|
||||||
|
|
||||||
const APP_COLORS = {
|
const PHONEPE_WALLETS = new Set(['phonepe_biz', 'phonepe_per']);
|
||||||
paytm: 'c-paytm', phonepe: 'c-phonepe', phonepe_pay: 'c-phonepe',
|
|
||||||
mobikwik: 'c-mobikwik', freecharge: 'c-freecharge', upi: 'c-upi',
|
|
||||||
};
|
|
||||||
|
|
||||||
const PHONEPE_WALLETS = new Set(['phonepe_biz', 'phonepe_per']);
|
function updateAppOptions(walletKey) {
|
||||||
|
const isPhonePeWallet = PHONEPE_WALLETS.has(walletKey);
|
||||||
|
const appSel = document.getElementById('app');
|
||||||
|
Array.from(appSel.options).forEach(opt => {
|
||||||
|
const isPhonePeOpt = opt.value === 'phonepe' || opt.value === 'phonepe_pay';
|
||||||
|
opt.disabled = isPhonePeOpt && !isPhonePeWallet;
|
||||||
|
});
|
||||||
|
// auto-switch away from disabled option
|
||||||
|
if (appSel.options[appSel.selectedIndex].disabled) {
|
||||||
|
appSel.value = 'paytm';
|
||||||
|
}
|
||||||
|
// auto-select recommended PhonePe scheme
|
||||||
|
if (isPhonePeWallet && appSel.value !== 'phonepe' && appSel.value !== 'phonepe_pay') {
|
||||||
|
appSel.value = walletKey === 'phonepe_biz' ? 'phonepe_pay' : 'phonepe';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function updateAppOptions(walletKey) {
|
function update() {
|
||||||
const isPhonePeWallet = PHONEPE_WALLETS.has(walletKey);
|
updateAppOptions(document.getElementById('wallet').value);
|
||||||
const appSel = document.getElementById('app');
|
|
||||||
Array.from(appSel.options).forEach(opt => {
|
|
||||||
const isPhonePeOpt = opt.value === 'phonepe' || opt.value === 'phonepe_pay';
|
|
||||||
opt.disabled = isPhonePeOpt && !isPhonePeWallet;
|
|
||||||
});
|
|
||||||
// auto-switch away from disabled option
|
|
||||||
if (appSel.options[appSel.selectedIndex].disabled) {
|
|
||||||
appSel.value = 'paytm';
|
|
||||||
}
|
|
||||||
// auto-select recommended PhonePe scheme
|
|
||||||
if (isPhonePeWallet && appSel.value !== 'phonepe' && appSel.value !== 'phonepe_pay') {
|
|
||||||
appSel.value = walletKey === 'phonepe_biz' ? 'phonepe_pay' : 'phonepe';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function update() {
|
const walletKey = document.getElementById('wallet').value;
|
||||||
updateAppOptions(document.getElementById('wallet').value);
|
const app = document.getElementById('app').value;
|
||||||
|
const am = document.getElementById('amount').value || '51';
|
||||||
|
const w = WALLETS[walletKey];
|
||||||
|
|
||||||
const walletKey = document.getElementById('wallet').value;
|
const warnEl = document.getElementById('warn-box');
|
||||||
const app = document.getElementById('app').value;
|
let warnMsg = w.warn || '';
|
||||||
const am = document.getElementById('amount').value || '51';
|
if (walletKey === 'phonepe_biz' && app === 'phonepe') {
|
||||||
const w = WALLETS[walletKey];
|
warnMsg = (warnMsg ? warnMsg + '\n' : '') + '提示:PhonePe Business 建议用 PhonePe (pay) 而非 native p2p。';
|
||||||
|
}
|
||||||
|
if (walletKey === 'phonepe_per' && app === 'phonepe_pay') {
|
||||||
|
warnMsg = (warnMsg ? warnMsg + '\n' : '') + '提示:PhonePe 个人收款建议用 PhonePe (native p2p)。';
|
||||||
|
}
|
||||||
|
if (warnMsg) {
|
||||||
|
warnEl.textContent = warnMsg.startsWith('⚠') ? warnMsg : '⚠ ' + warnMsg;
|
||||||
|
warnEl.style.display = 'block';
|
||||||
|
} else {
|
||||||
|
warnEl.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
const warnEl = document.getElementById('warn-box');
|
const link = w.pa
|
||||||
let warnMsg = w.warn || '';
|
? APP_SCHEMES[app](w.pa, encodeURIComponent(w.pn), am, w.extra())
|
||||||
if (walletKey === 'phonepe_biz' && app === 'phonepe') {
|
: '';
|
||||||
warnMsg = (warnMsg ? warnMsg + '\n' : '') + '提示:PhonePe Business 建议用 PhonePe (pay) 而非 native p2p。';
|
|
||||||
}
|
|
||||||
if (walletKey === 'phonepe_per' && app === 'phonepe_pay') {
|
|
||||||
warnMsg = (warnMsg ? warnMsg + '\n' : '') + '提示:PhonePe 个人收款建议用 PhonePe (native p2p)。';
|
|
||||||
}
|
|
||||||
if (warnMsg) {
|
|
||||||
warnEl.textContent = warnMsg.startsWith('⚠') ? warnMsg : '⚠ ' + warnMsg;
|
|
||||||
warnEl.style.display = 'block';
|
|
||||||
} else {
|
|
||||||
warnEl.style.display = 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
const link = w.pa
|
document.getElementById('info-pn').textContent = w.pn || '—';
|
||||||
? APP_SCHEMES[app](w.pa, encodeURIComponent(w.pn), am, w.extra())
|
document.getElementById('info-pa').textContent = w.pa || '—';
|
||||||
: '';
|
document.getElementById('info-am').textContent = w.pa ? `₹ ${am}` : '—';
|
||||||
|
document.getElementById('link-display').textContent = link || '—';
|
||||||
|
|
||||||
document.getElementById('info-pn').textContent = w.pn || '—';
|
const btn = document.getElementById('pay-btn');
|
||||||
document.getElementById('info-pa').textContent = w.pa || '—';
|
btn.href = link || '#';
|
||||||
document.getElementById('info-am').textContent = w.pa ? `₹ ${am}` : '—';
|
btn.className = `pay-btn ${APP_COLORS[app]}`;
|
||||||
document.getElementById('link-display').textContent = link || '—';
|
|
||||||
|
|
||||||
const btn = document.getElementById('pay-btn');
|
const el = document.getElementById('qrcode');
|
||||||
btn.href = link || '#';
|
el.innerHTML = '';
|
||||||
btn.className = `pay-btn ${APP_COLORS[app]}`;
|
if (link) {
|
||||||
|
new QRCode(el, { text: link, width: 200, height: 200, correctLevel: QRCode.CorrectLevel.M });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
document.getElementById('pay-btn').addEventListener('click', function (e) {
|
||||||
|
const href = this.getAttribute('href');
|
||||||
|
if (!href || href === '#') return;
|
||||||
|
e.preventDefault();
|
||||||
|
try {
|
||||||
|
window.location.href = href;
|
||||||
|
} catch (_) { }
|
||||||
|
});
|
||||||
|
|
||||||
const el = document.getElementById('qrcode');
|
document.getElementById('amount').addEventListener('input', update);
|
||||||
el.innerHTML = '';
|
update();
|
||||||
if (link) {
|
</script>
|
||||||
new QRCode(el, { text: link, width: 200, height: 200, correctLevel: QRCode.CorrectLevel.M });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let autoTimer = null;
|
|
||||||
|
|
||||||
function scheduleAutoClick() {
|
|
||||||
if (autoTimer) clearTimeout(autoTimer);
|
|
||||||
autoTimer = setTimeout(() => {
|
|
||||||
const btn = document.getElementById('pay-btn');
|
|
||||||
if (!btn.href || btn.href === '#' || btn.href.endsWith('#')) return;
|
|
||||||
|
|
||||||
const app = document.getElementById('app').value;
|
|
||||||
if (app === 'freecharge') {
|
|
||||||
// freechargeupi:// 不可用时 fallback 到 upi://
|
|
||||||
const fallbackTimer = setTimeout(() => {
|
|
||||||
const w = WALLETS[document.getElementById('wallet').value];
|
|
||||||
const am = document.getElementById('amount').value || '51';
|
|
||||||
const fallback = `upi://pay?pa=${w.pa}&pn=${encodeURIComponent(w.pn)}&am=${am}&cu=INR${w.extra()}`;
|
|
||||||
window.location.href = fallback;
|
|
||||||
}, 2500);
|
|
||||||
window.location.href = btn.href;
|
|
||||||
// 如果页面还在(没跳走),说明跳转失败,fallback 会触发
|
|
||||||
window.addEventListener('blur', () => clearTimeout(fallbackTimer), { once: true });
|
|
||||||
} else {
|
|
||||||
btn.click();
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('wallet').addEventListener('change', () => { update(); scheduleAutoClick(); });
|
|
||||||
document.getElementById('app').addEventListener('change', () => { update(); scheduleAutoClick(); });
|
|
||||||
document.getElementById('amount').addEventListener('input', update);
|
|
||||||
update();
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user