[Feature Request] Waffo Pancake gateway — full integration with subscription support + admin catalog binding flow (#4935)
This commit is contained in:
+5
@@ -0,0 +1,5 @@
|
||||
<svg width="27" height="27" viewBox="0 0 27 27" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12.8965 17.8787L11.2995 12.6132L10.1344 8.7762C9.97497 8.25193 9.4909 7.89355 8.94204 7.89355H4.41838C3.89937 7.89355 3.52838 8.39249 3.67767 8.88637L6.0675 16.7643C6.37941 17.7907 7.32849 18.4928 8.40398 18.4928H12.4398C12.7599 18.4922 12.9893 18.1845 12.8965 17.8787ZM7.47396 10.6301C7.11059 10.7302 6.71038 10.4345 6.58079 9.96909C6.4512 9.50371 6.64177 9.04403 7.00514 8.94399C7.36851 8.84395 7.76745 9.13964 7.89641 9.60502C8.026 10.0717 7.83733 10.5301 7.47396 10.6301Z" fill="white"/>
|
||||
<path d="M13.0281 18.269C12.8777 18.4077 12.6794 18.4926 12.4646 18.4927H12.4382C12.7588 18.4926 12.9887 18.1847 12.8962 17.8784L11.2996 12.6128L11.3054 12.5923L13.0281 18.269ZM14.5144 13.771V13.7729L13.2615 17.9028C13.2401 17.973 13.2071 18.0369 13.1697 18.0972L11.4021 12.271L12.4626 8.77588C12.6221 8.25169 13.1063 7.89317 13.655 7.89307H16.2976L14.5144 13.771Z" fill="white"/>
|
||||
<path d="M19.5133 18.4932H16.8707C16.3221 18.493 15.8378 18.135 15.6783 17.6104L14.61 14.0859L16.3883 8.19336L17.7311 12.6133L19.1617 7.89355H22.7291L19.5133 18.4932Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
+5
@@ -0,0 +1,5 @@
|
||||
<svg width="27" height="27" viewBox="0 0 27 27" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12.8967 17.8789L11.2996 12.6135L10.1346 8.77644C9.97511 8.25218 9.49104 7.8938 8.94218 7.8938H4.4185C3.8995 7.8938 3.5285 8.39274 3.67779 8.88662L6.06763 16.7646C6.37954 17.7909 7.32862 18.4931 8.40411 18.4931H12.4399C12.7601 18.4925 12.9894 18.1848 12.8967 17.8789ZM7.47409 10.6304C7.11073 10.7304 6.71051 10.4347 6.58092 9.96934C6.45133 9.50396 6.64191 9.04428 7.00527 8.94423C7.36864 8.84419 7.76758 9.13989 7.89654 9.60527C8.02613 10.0719 7.83746 10.5303 7.47409 10.6304Z" fill="black"/>
|
||||
<path d="M13.0278 18.2703C12.8774 18.4086 12.679 18.4929 12.4643 18.4929H12.4379C12.7587 18.4929 12.9886 18.1851 12.8959 17.8787L11.2993 12.613L11.3051 12.5925L13.0278 18.2703ZM16.2973 7.89331L14.5151 13.7712V13.7732L13.2612 17.9031C13.2397 17.9736 13.207 18.0379 13.1694 18.0984L11.4018 12.2712L12.4633 8.77612C12.6228 8.25186 13.1068 7.89331 13.6557 7.89331H16.2973Z" fill="black"/>
|
||||
<path d="M22.7283 7.89478L19.5134 18.4934H16.8718C16.323 18.4934 15.8389 18.1355 15.6794 17.6106L14.6101 14.0862L16.3884 8.19458L17.7312 12.6145L19.1619 7.89478H22.7283Z" fill="black"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
+7
-22
@@ -53,16 +53,9 @@ const PaymentSetting = () => {
|
||||
StripeMinTopUp: 1,
|
||||
StripePromotionCodesEnabled: false,
|
||||
|
||||
WaffoPancakeEnabled: false,
|
||||
WaffoPancakeSandbox: false,
|
||||
WaffoPancakeMerchantID: '',
|
||||
WaffoPancakePrivateKey: '',
|
||||
WaffoPancakeStoreID: '',
|
||||
WaffoPancakeProductID: '',
|
||||
WaffoPancakeReturnURL: '',
|
||||
WaffoPancakeCurrency: 'USD',
|
||||
WaffoPancakeUnitPrice: 1.0,
|
||||
WaffoPancakeMinTopUp: 1,
|
||||
'payment_setting.compliance_confirmed': false,
|
||||
'payment_setting.compliance_terms_version': '',
|
||||
'payment_setting.compliance_confirmed_at': 0,
|
||||
@@ -171,21 +164,13 @@ const PaymentSetting = () => {
|
||||
case 'MinTopUp':
|
||||
case 'StripeUnitPrice':
|
||||
case 'StripeMinTopUp':
|
||||
case 'WaffoPancakeUnitPrice':
|
||||
case 'WaffoPancakeMinTopUp':
|
||||
newInputs[item.key] = parseFloat(item.value);
|
||||
break;
|
||||
case 'WaffoPancakeMerchantID':
|
||||
case 'WaffoPancakePrivateKey':
|
||||
case 'WaffoPancakeStoreID':
|
||||
case 'WaffoPancakeProductID':
|
||||
case 'WaffoPancakeReturnURL':
|
||||
case 'WaffoPancakeCurrency':
|
||||
newInputs[item.key] = item.value;
|
||||
break;
|
||||
case 'WaffoPancakeSandbox':
|
||||
newInputs[item.key] = toBoolean(item.value);
|
||||
break;
|
||||
default:
|
||||
if (item.key.endsWith('Enabled')) {
|
||||
newInputs[item.key] = toBoolean(item.value);
|
||||
@@ -320,6 +305,13 @@ const PaymentSetting = () => {
|
||||
hideSectionTitle
|
||||
/>
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane tab={t('Waffo Pancake 设置')} itemKey='waffo-pancake'>
|
||||
<SettingsPaymentGatewayWaffoPancake
|
||||
options={inputs}
|
||||
refresh={onRefresh}
|
||||
hideSectionTitle
|
||||
/>
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane tab={t('Waffo 设置')} itemKey='waffo'>
|
||||
<SettingsPaymentGatewayWaffo
|
||||
options={inputs}
|
||||
@@ -327,13 +319,6 @@ const PaymentSetting = () => {
|
||||
hideSectionTitle
|
||||
/>
|
||||
</Tabs.TabPane>
|
||||
{/*<Tabs.TabPane tab={t('Waffo Pancake 设置')} itemKey='waffo-pancake'>*/}
|
||||
{/* <SettingsPaymentGatewayWaffoPancake*/}
|
||||
{/* options={inputs}*/}
|
||||
{/* refresh={onRefresh}*/}
|
||||
{/* hideSectionTitle*/}
|
||||
{/* />*/}
|
||||
{/*</Tabs.TabPane>*/}
|
||||
</Tabs>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
+14
-3
@@ -47,6 +47,7 @@ import {
|
||||
} from 'lucide-react';
|
||||
import { IconGift } from '@douyinfe/semi-icons';
|
||||
import { useMinimumLoadingTime } from '../../hooks/common/useMinimumLoadingTime';
|
||||
import { useActualTheme } from '../../context/Theme';
|
||||
import { getCurrencyConfig } from '../../helpers/render';
|
||||
import SubscriptionPlansCard from './SubscriptionPlansCard';
|
||||
|
||||
@@ -102,6 +103,7 @@ const RechargeCard = ({
|
||||
const redeemFormApiRef = useRef(null);
|
||||
const initialTabSetRef = useRef(false);
|
||||
const showAmountSkeleton = useMinimumLoadingTime(amountLoading);
|
||||
const actualTheme = useActualTheme();
|
||||
const [activeTab, setActiveTab] = useState('topup');
|
||||
const shouldShowSubscription =
|
||||
!subscriptionLoading && subscriptionPlans.length > 0;
|
||||
@@ -355,9 +357,18 @@ const RechargeCard = ({
|
||||
}}
|
||||
/>
|
||||
) : payMethod.type === 'waffo_pancake' ? (
|
||||
<CreditCard
|
||||
size={18}
|
||||
color='var(--semi-color-primary)'
|
||||
<img
|
||||
src={
|
||||
actualTheme === 'dark'
|
||||
? '/waffo-logo-dark.svg'
|
||||
: '/waffo-logo-light.svg'
|
||||
}
|
||||
alt='Waffo'
|
||||
style={{
|
||||
width: 18,
|
||||
height: 18,
|
||||
objectFit: 'contain',
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<CreditCard
|
||||
|
||||
+23
-2
@@ -40,6 +40,23 @@ import TransferModal from './modals/TransferModal';
|
||||
import PaymentConfirmModal from './modals/PaymentConfirmModal';
|
||||
import TopupHistoryModal from './modals/TopupHistoryModal';
|
||||
|
||||
// Reject non-navigable schemes (e.g. javascript:, data:) and relative URLs.
|
||||
// Only http / https are allowed for backend-provided redirect targets.
|
||||
// Mirrors isSafeHttpCheckoutUrl in the default frontend's
|
||||
// features/wallet/hooks/use-waffo-pancake-payment.ts.
|
||||
function isSafeHttpCheckoutUrl(value) {
|
||||
const trimmed = (value || '').trim();
|
||||
if (!trimmed) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const u = new URL(trimmed);
|
||||
return u.protocol === 'http:' || u.protocol === 'https:';
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const TopUp = () => {
|
||||
const { t } = useTranslation();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
@@ -454,8 +471,12 @@ const TopUp = () => {
|
||||
const { message, data } = res.data;
|
||||
if (message === 'success') {
|
||||
const checkoutUrl = data?.checkout_url || '';
|
||||
if (checkoutUrl) {
|
||||
window.open(checkoutUrl, '_blank');
|
||||
if (checkoutUrl && isSafeHttpCheckoutUrl(checkoutUrl)) {
|
||||
// In-tab redirect (not window.open) — popup blocker fires after
|
||||
// the await loses user-gesture context.
|
||||
window.location.href = checkoutUrl;
|
||||
} else if (checkoutUrl) {
|
||||
showError(t('支付跳转地址不安全'));
|
||||
} else {
|
||||
showError(t('支付请求失败'));
|
||||
}
|
||||
|
||||
Vendored
+1
@@ -1720,6 +1720,7 @@
|
||||
"支付渠道": "Payment Channels",
|
||||
"支付设置": "Payment",
|
||||
"支付请求失败": "Payment request failed",
|
||||
"支付跳转地址不安全": "Unsafe payment redirect URL",
|
||||
"支付返回地址": "Return URL",
|
||||
"支付金额": "Payment Amount",
|
||||
"支持 Ctrl+V 粘贴图片": "Supports Ctrl+V to paste images",
|
||||
|
||||
Vendored
+1
@@ -1154,6 +1154,7 @@
|
||||
"支付方式": "支付方式",
|
||||
"支付设置": "支付设置",
|
||||
"支付请求失败": "支付请求失败",
|
||||
"支付跳转地址不安全": "支付跳转地址不安全",
|
||||
"支付金额": "支付金额",
|
||||
"支持 Ctrl+V 粘贴图片": "支持 Ctrl+V 粘贴图片",
|
||||
"支持6位TOTP验证码或8位备用码,可到`个人设置-安全设置-两步验证设置`配置或查看。": "支持6位TOTP验证码或8位备用码,可到`个人设置-安全设置-两步验证设置`配置或查看。",
|
||||
|
||||
+30
-239
@@ -26,25 +26,14 @@ import {
|
||||
showSuccess,
|
||||
} from '../../../helpers';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { BookOpen, TriangleAlert } from 'lucide-react';
|
||||
import { BookOpen } from 'lucide-react';
|
||||
|
||||
const defaultInputs = {
|
||||
WaffoPancakeEnabled: false,
|
||||
WaffoPancakeSandbox: false,
|
||||
WaffoPancakeMerchantID: '',
|
||||
WaffoPancakePrivateKey: '',
|
||||
WaffoPancakeWebhookPublicKey: '',
|
||||
WaffoPancakeWebhookTestKey: '',
|
||||
WaffoPancakeStoreID: '',
|
||||
WaffoPancakeProductID: '',
|
||||
WaffoPancakeReturnURL: '',
|
||||
WaffoPancakeCurrency: 'USD',
|
||||
WaffoPancakeUnitPrice: 1.0,
|
||||
WaffoPancakeMinTopUp: 1,
|
||||
};
|
||||
|
||||
const toBoolean = (value) => value === true || value === 'true';
|
||||
|
||||
export default function SettingsPaymentGatewayWaffoPancake(props) {
|
||||
const { t } = useTranslation();
|
||||
const sectionTitle = props.hideSectionTitle
|
||||
@@ -58,26 +47,9 @@ export default function SettingsPaymentGatewayWaffoPancake(props) {
|
||||
if (!props.options || !formApiRef.current) return;
|
||||
|
||||
const currentInputs = {
|
||||
WaffoPancakeEnabled: toBoolean(props.options.WaffoPancakeEnabled),
|
||||
WaffoPancakeSandbox: toBoolean(props.options.WaffoPancakeSandbox),
|
||||
WaffoPancakeMerchantID: props.options.WaffoPancakeMerchantID || '',
|
||||
WaffoPancakePrivateKey: props.options.WaffoPancakePrivateKey || '',
|
||||
WaffoPancakeWebhookPublicKey:
|
||||
props.options.WaffoPancakeWebhookPublicKey || '',
|
||||
WaffoPancakeWebhookTestKey:
|
||||
props.options.WaffoPancakeWebhookTestKey || '',
|
||||
WaffoPancakeStoreID: props.options.WaffoPancakeStoreID || '',
|
||||
WaffoPancakeProductID: props.options.WaffoPancakeProductID || '',
|
||||
WaffoPancakeReturnURL: props.options.WaffoPancakeReturnURL || '',
|
||||
WaffoPancakeCurrency: props.options.WaffoPancakeCurrency || 'USD',
|
||||
WaffoPancakeUnitPrice:
|
||||
props.options.WaffoPancakeUnitPrice !== undefined
|
||||
? parseFloat(props.options.WaffoPancakeUnitPrice)
|
||||
: 1.0,
|
||||
WaffoPancakeMinTopUp:
|
||||
props.options.WaffoPancakeMinTopUp !== undefined
|
||||
? parseFloat(props.options.WaffoPancakeMinTopUp)
|
||||
: 1,
|
||||
};
|
||||
|
||||
setInputs(currentInputs);
|
||||
@@ -93,90 +65,23 @@ export default function SettingsPaymentGatewayWaffoPancake(props) {
|
||||
...inputs,
|
||||
...(formApiRef.current?.getValues?.() || {}),
|
||||
};
|
||||
values.WaffoPancakeEnabled = toBoolean(values.WaffoPancakeEnabled);
|
||||
values.WaffoPancakeSandbox = toBoolean(values.WaffoPancakeSandbox);
|
||||
const currentWebhookField = values.WaffoPancakeSandbox
|
||||
? 'WaffoPancakeWebhookTestKey'
|
||||
: 'WaffoPancakeWebhookPublicKey';
|
||||
const currentWebhookLabel = values.WaffoPancakeSandbox
|
||||
? t('Webhook 公钥(测试环境)')
|
||||
: t('Webhook 公钥(生产环境)');
|
||||
|
||||
if (values.WaffoPancakeEnabled && !values.WaffoPancakeMerchantID.trim()) {
|
||||
showError(t('请输入商户 ID'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (values.WaffoPancakeEnabled && !values.WaffoPancakeStoreID.trim()) {
|
||||
showError(t('请输入 Store ID'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (values.WaffoPancakeEnabled && !values.WaffoPancakeProductID.trim()) {
|
||||
showError(t('请输入 Product ID'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
values.WaffoPancakeEnabled &&
|
||||
!String(values[currentWebhookField] || '').trim()
|
||||
) {
|
||||
showError(currentWebhookLabel);
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
values.WaffoPancakeEnabled &&
|
||||
Number(values.WaffoPancakeUnitPrice) <= 0
|
||||
) {
|
||||
showError(t('充值价格必须大于 0'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (values.WaffoPancakeEnabled && Number(values.WaffoPancakeMinTopUp) < 1) {
|
||||
showError(t('最低充值美元数量必须大于 0'));
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
// Classic admin only persists the three operator-typed fields.
|
||||
// Store/Product binding is handled exclusively by the default
|
||||
// frontend's catalog flow (see waffo-pancake-settings-section.tsx)
|
||||
// because picking entities from a live catalog needs the Select +
|
||||
// dependent-dropdown UX that the classic Semi-UI page doesn't have.
|
||||
const options = [
|
||||
{
|
||||
key: 'WaffoPancakeEnabled',
|
||||
value: values.WaffoPancakeEnabled ? 'true' : 'false',
|
||||
},
|
||||
{
|
||||
key: 'WaffoPancakeSandbox',
|
||||
value: values.WaffoPancakeSandbox ? 'true' : 'false',
|
||||
},
|
||||
{
|
||||
key: 'WaffoPancakeMerchantID',
|
||||
value: values.WaffoPancakeMerchantID || '',
|
||||
},
|
||||
{
|
||||
key: 'WaffoPancakeStoreID',
|
||||
value: values.WaffoPancakeStoreID || '',
|
||||
},
|
||||
{
|
||||
key: 'WaffoPancakeProductID',
|
||||
value: values.WaffoPancakeProductID || '',
|
||||
},
|
||||
{
|
||||
key: 'WaffoPancakeReturnURL',
|
||||
value: removeTrailingSlash(values.WaffoPancakeReturnURL || ''),
|
||||
},
|
||||
{
|
||||
key: 'WaffoPancakeCurrency',
|
||||
value: values.WaffoPancakeCurrency || 'USD',
|
||||
},
|
||||
{
|
||||
key: 'WaffoPancakeUnitPrice',
|
||||
value: String(values.WaffoPancakeUnitPrice),
|
||||
},
|
||||
{
|
||||
key: 'WaffoPancakeMinTopUp',
|
||||
value: String(values.WaffoPancakeMinTopUp),
|
||||
},
|
||||
];
|
||||
|
||||
if ((values.WaffoPancakePrivateKey || '').trim()) {
|
||||
@@ -186,20 +91,6 @@ export default function SettingsPaymentGatewayWaffoPancake(props) {
|
||||
});
|
||||
}
|
||||
|
||||
if ((values.WaffoPancakeWebhookPublicKey || '').trim()) {
|
||||
options.push({
|
||||
key: 'WaffoPancakeWebhookPublicKey',
|
||||
value: values.WaffoPancakeWebhookPublicKey,
|
||||
});
|
||||
}
|
||||
|
||||
if ((values.WaffoPancakeWebhookTestKey || '').trim()) {
|
||||
options.push({
|
||||
key: 'WaffoPancakeWebhookTestKey',
|
||||
value: values.WaffoPancakeWebhookTestKey,
|
||||
});
|
||||
}
|
||||
|
||||
const results = await Promise.all(
|
||||
options.map((opt) =>
|
||||
API.put('/api/option/', {
|
||||
@@ -237,103 +128,43 @@ export default function SettingsPaymentGatewayWaffoPancake(props) {
|
||||
icon={<BookOpen size={16} />}
|
||||
description={
|
||||
<>
|
||||
Waffo Pancake 的商户、商品和签名密钥请
|
||||
Waffo Pancake 商户 ID 与私钥请在
|
||||
<a
|
||||
href='https://docs.waffo.ai'
|
||||
href='https://pancake.waffo.ai/merchant/dashboard'
|
||||
target='_blank'
|
||||
rel='noreferrer'
|
||||
>
|
||||
点击此处
|
||||
Waffo Pancake 控制台
|
||||
</a>
|
||||
获取,建议先在测试环境完成联调。
|
||||
获取,保存后系统会自动在该商户名下创建 Store + Product,无需手动配置;
|
||||
环境(test / 生产)由你粘贴的 API 私钥本身决定。
|
||||
请在 Pancake 控制台把下面两个回调地址分别注册到 Test Mode 和 Production Mode
|
||||
两个 webhook 位置,分开走避免测试流量污染生产数据:
|
||||
<br />
|
||||
{t('回调地址')}:
|
||||
{t('Test 回调地址')}:
|
||||
{props.options.ServerAddress
|
||||
? removeTrailingSlash(props.options.ServerAddress)
|
||||
: t('网站地址')}
|
||||
/api/waffo-pancake/webhook
|
||||
/api/waffo-pancake/webhook/test
|
||||
<br />
|
||||
{t('Production 回调地址')}:
|
||||
{props.options.ServerAddress
|
||||
? removeTrailingSlash(props.options.ServerAddress)
|
||||
: t('网站地址')}
|
||||
/api/waffo-pancake/webhook/prod
|
||||
</>
|
||||
}
|
||||
style={{ marginBottom: 12 }}
|
||||
/>
|
||||
<Banner
|
||||
type='warning'
|
||||
icon={<TriangleAlert size={16} />}
|
||||
description={t(
|
||||
'请确认 Merchant、Store、Product 和所选环境密钥一致。',
|
||||
)}
|
||||
style={{ marginBottom: 16 }}
|
||||
/>
|
||||
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 24, xl: 24, xxl: 24 }}>
|
||||
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
|
||||
<Form.Switch
|
||||
field='WaffoPancakeEnabled'
|
||||
label={t('启用 Waffo Pancake')}
|
||||
checkedText='|'
|
||||
uncheckedText='〇'
|
||||
/>
|
||||
</Col>
|
||||
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
|
||||
<Form.Switch
|
||||
field='WaffoPancakeSandbox'
|
||||
label={t('沙盒模式')}
|
||||
checkedText='|'
|
||||
uncheckedText='〇'
|
||||
extraText={t('用于切换当前下单和回调校验所使用的环境')}
|
||||
/>
|
||||
</Col>
|
||||
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
|
||||
<Form.Input
|
||||
field='WaffoPancakeCurrency'
|
||||
label={t('货币')}
|
||||
placeholder='USD'
|
||||
extraText={t('默认使用 USD 结算')}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Row
|
||||
gutter={{ xs: 8, sm: 16, md: 24, lg: 24, xl: 24, xxl: 24 }}
|
||||
style={{ marginTop: 16 }}
|
||||
>
|
||||
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
|
||||
<Form.Input
|
||||
field='WaffoPancakeMerchantID'
|
||||
label={t('商户 ID')}
|
||||
placeholder={t('例如:MER_xxx')}
|
||||
extraText={t('请填写当前环境对应的商户 ID')}
|
||||
/>
|
||||
</Col>
|
||||
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
|
||||
<Form.Input
|
||||
field='WaffoPancakeStoreID'
|
||||
label={t('Store ID')}
|
||||
placeholder={t('例如:STO_xxx')}
|
||||
extraText={t('请填写当前环境对应的 Store ID')}
|
||||
/>
|
||||
</Col>
|
||||
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
|
||||
<Form.Input
|
||||
field='WaffoPancakeProductID'
|
||||
label={t('Product ID')}
|
||||
placeholder={t('例如:PROD_xxx')}
|
||||
extraText={t('请填写当前环境对应的 Product ID')}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Row
|
||||
gutter={{ xs: 8, sm: 16, md: 24, lg: 24, xl: 24, xxl: 24 }}
|
||||
style={{ marginTop: 16 }}
|
||||
>
|
||||
<Col xs={24} sm={24} md={12} lg={12} xl={12}>
|
||||
<Form.TextArea
|
||||
field='WaffoPancakePrivateKey'
|
||||
label={t('API 私钥')}
|
||||
placeholder={t('填写后覆盖当前私钥,留空表示保持当前不变')}
|
||||
extraText={t('保存后不会回显,请填写当前环境对应的 API 私钥')}
|
||||
type='password'
|
||||
autosize={{ minRows: 4, maxRows: 8 }}
|
||||
<Form.Input
|
||||
field='WaffoPancakeMerchantID'
|
||||
label={t('商户 ID')}
|
||||
placeholder={t('例如:MER_xxx')}
|
||||
/>
|
||||
</Col>
|
||||
<Col xs={24} sm={24} md={12} lg={12} xl={12}>
|
||||
@@ -341,7 +172,6 @@ export default function SettingsPaymentGatewayWaffoPancake(props) {
|
||||
field='WaffoPancakeReturnURL'
|
||||
label={t('支付返回地址')}
|
||||
placeholder={t('例如:https://example.com/console/topup')}
|
||||
extraText={t('留空则自动使用当前站点的默认充值页地址')}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
@@ -350,55 +180,16 @@ export default function SettingsPaymentGatewayWaffoPancake(props) {
|
||||
gutter={{ xs: 8, sm: 16, md: 24, lg: 24, xl: 24, xxl: 24 }}
|
||||
style={{ marginTop: 16 }}
|
||||
>
|
||||
<Col xs={24} sm={24} md={12} lg={12} xl={12}>
|
||||
<Col xs={24}>
|
||||
<Form.TextArea
|
||||
field='WaffoPancakeWebhookPublicKey'
|
||||
label={t('Webhook 公钥(生产环境)')}
|
||||
placeholder={t(
|
||||
'填写后覆盖当前生产环境 Webhook 公钥,留空表示保持当前不变',
|
||||
)}
|
||||
extraText={t('用于校验生产环境的 Waffo Pancake Webhook 签名')}
|
||||
field='WaffoPancakePrivateKey'
|
||||
label={t('API 私钥')}
|
||||
placeholder={t('填写后覆盖当前私钥,留空表示保持当前不变')}
|
||||
extraText={t('⚠ 测试 / 生产环境由你粘进来的 API 私钥本身决定——集成阶段用 Test Key,正式上线时再换成 Production Key')}
|
||||
type='password'
|
||||
autosize={{ minRows: 4, maxRows: 8 }}
|
||||
/>
|
||||
</Col>
|
||||
<Col xs={24} sm={24} md={12} lg={12} xl={12}>
|
||||
<Form.TextArea
|
||||
field='WaffoPancakeWebhookTestKey'
|
||||
label={t('Webhook 公钥(测试环境)')}
|
||||
placeholder={t(
|
||||
'填写后覆盖当前测试环境 Webhook 公钥,留空表示保持当前不变',
|
||||
)}
|
||||
extraText={t('用于校验测试环境的 Waffo Pancake Webhook 签名')}
|
||||
type='password'
|
||||
autosize={{ minRows: 4, maxRows: 8 }}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Row
|
||||
gutter={{ xs: 8, sm: 16, md: 24, lg: 24, xl: 24, xxl: 24 }}
|
||||
style={{ marginTop: 16 }}
|
||||
>
|
||||
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
|
||||
<Form.InputNumber
|
||||
field='WaffoPancakeUnitPrice'
|
||||
precision={2}
|
||||
label={t('充值价格(x元/美金)')}
|
||||
placeholder={t('例如:7,就是7元/美金')}
|
||||
extraText={t('按 1 美元对应的站内价格填写')}
|
||||
min={0}
|
||||
/>
|
||||
</Col>
|
||||
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
|
||||
<Form.InputNumber
|
||||
field='WaffoPancakeMinTopUp'
|
||||
label={t('最低充值美元数量')}
|
||||
placeholder={t('例如:2,就是最低充值2$')}
|
||||
extraText={t('用户单次最少可充值的美元数量')}
|
||||
min={1}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Button onClick={submitWaffoPancakeSetting}>
|
||||
|
||||
Reference in New Issue
Block a user