fix(payment): resolve payment settings save logic and enable persistence
- Fix Bug 1: Always save all provider-specific fields regardless of currently selected provider in dropdown, preventing data loss when switching between Alipay/WeChat/ePay/Yipay configurations - Fix Bug 2: Add EpayEnabled/YipayEnabled backend Go variables and OptionMap entries so enable/disable checkboxes persist across page reloads - Fix white screen crash by wrapping orphan Col elements in proper Row - Add EpayEnabled/YipayEnabled to PaymentSetting.jsx initial state - Remove duplicate payment card imports for Stripe/Creem/Waffo/Alipay/Wechat
This commit is contained in:
parent
6fc114ec32
commit
82016579db
|
|
@ -102,6 +102,8 @@ func InitOptionMap() {
|
|||
common.OptionMap["YipayReturnUrl"] = operation_setting.YipayReturnUrl
|
||||
common.OptionMap["YipayRequestURL"] = operation_setting.YipayRequestURL
|
||||
common.OptionMap["YipayChannelExtra"] = operation_setting.YipayChannelExtra
|
||||
common.OptionMap["EpayEnabled"] = strconv.FormatBool(operation_setting.EpayEnabled)
|
||||
common.OptionMap["YipayEnabled"] = strconv.FormatBool(operation_setting.YipayEnabled)
|
||||
common.OptionMap["Price"] = strconv.FormatFloat(operation_setting.Price, 'f', -1, 64)
|
||||
common.OptionMap["USDExchangeRate"] = strconv.FormatFloat(operation_setting.USDExchangeRate, 'f', -1, 64)
|
||||
common.OptionMap["MinTopUp"] = strconv.Itoa(operation_setting.MinTopUp)
|
||||
|
|
@ -495,6 +497,10 @@ func updateOptionMap(key string, value string) (err error) {
|
|||
case "YipayChannelExtra":
|
||||
operation_setting.YipayChannelExtra = strings.TrimSpace(value)
|
||||
common.OptionMap[key] = operation_setting.YipayChannelExtra
|
||||
case "EpayEnabled":
|
||||
operation_setting.EpayEnabled = value == "true"
|
||||
case "YipayEnabled":
|
||||
operation_setting.YipayEnabled = value == "true"
|
||||
case "Price":
|
||||
operation_setting.Price, _ = strconv.ParseFloat(value, 64)
|
||||
case "USDExchangeRate":
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ var CustomCallbackAddress = ""
|
|||
var EpayId = ""
|
||||
var EpayKey = ""
|
||||
var YipayAppSecret = ""
|
||||
var EpayEnabled = false
|
||||
var YipayEnabled = false
|
||||
var OnlinePayProvider = "yipay"
|
||||
var Price = 7.3
|
||||
var MinTopUp = 1
|
||||
|
|
|
|||
|
|
@ -21,11 +21,7 @@ import React, { useEffect, useState } from "react";
|
|||
import { Card, Spin } from "@douyinfe/semi-ui";
|
||||
import SettingsGeneralPayment from "../../pages/Setting/Payment/SettingsGeneralPayment";
|
||||
import SettingsPaymentGateway from "../../pages/Setting/Payment/SettingsPaymentGateway";
|
||||
import SettingsPaymentGatewayStripe from "../../pages/Setting/Payment/SettingsPaymentGatewayStripe";
|
||||
import SettingsPaymentGatewayCreem from "../../pages/Setting/Payment/SettingsPaymentGatewayCreem";
|
||||
import SettingsPaymentGatewayWaffo from "../../pages/Setting/Payment/SettingsPaymentGatewayWaffo";
|
||||
import SettingsPaymentGatewayAlipay from "../../pages/Setting/Payment/SettingsPaymentGatewayAlipay";
|
||||
import SettingsPaymentGatewayWechat from "../../pages/Setting/Payment/SettingsPaymentGatewayWechat";
|
||||
|
||||
import { API, showError, toBoolean } from "../../helpers";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
|
|
@ -45,6 +41,8 @@ const PaymentSetting = () => {
|
|||
YipayReturnUrl: "",
|
||||
YipayChannelExtra: "",
|
||||
YipayRequestURL: "",
|
||||
EpayEnabled: false,
|
||||
YipayEnabled: false,
|
||||
Price: 7.3,
|
||||
MinTopUp: 1,
|
||||
TopupGroupRatio: "",
|
||||
|
|
@ -53,13 +51,6 @@ const PaymentSetting = () => {
|
|||
AmountOptions: "",
|
||||
AmountDiscount: "",
|
||||
|
||||
StripeApiSecret: "",
|
||||
StripeWebhookSecret: "",
|
||||
StripePriceId: "",
|
||||
StripeUnitPrice: 8.0,
|
||||
StripeMinTopUp: 1,
|
||||
StripePromotionCodesEnabled: false,
|
||||
|
||||
AlipayEnabled: false,
|
||||
AlipayAppId: "",
|
||||
AlipayPrivateKey: "",
|
||||
|
|
@ -131,10 +122,6 @@ const PaymentSetting = () => {
|
|||
break;
|
||||
case "Price":
|
||||
case "MinTopUp":
|
||||
case "StripeUnitPrice":
|
||||
case "StripeMinTopUp":
|
||||
newInputs[item.key] = parseFloat(item.value);
|
||||
break;
|
||||
case "YipayAppSecret":
|
||||
newInputs[item.key] =
|
||||
item.value != null && item.value !== undefined
|
||||
|
|
@ -181,21 +168,6 @@ const PaymentSetting = () => {
|
|||
<Card style={{ marginTop: "10px" }}>
|
||||
<SettingsPaymentGateway options={inputs} refresh={onRefresh} />
|
||||
</Card>
|
||||
<Card style={{ marginTop: "10px" }}>
|
||||
<SettingsPaymentGatewayStripe options={inputs} refresh={onRefresh} />
|
||||
</Card>
|
||||
<Card style={{ marginTop: "10px" }}>
|
||||
<SettingsPaymentGatewayCreem options={inputs} refresh={onRefresh} />
|
||||
</Card>
|
||||
<Card style={{ marginTop: "10px" }}>
|
||||
<SettingsPaymentGatewayWaffo options={inputs} refresh={onRefresh} />
|
||||
</Card>
|
||||
<Card style={{ marginTop: "10px" }}>
|
||||
<SettingsPaymentGatewayAlipay options={inputs} refresh={onRefresh} />
|
||||
</Card>
|
||||
<Card style={{ marginTop: "10px" }}>
|
||||
<SettingsPaymentGatewayWechat options={inputs} refresh={onRefresh} />
|
||||
</Card>
|
||||
</Spin>
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -70,6 +70,8 @@ const RechargeCard = ({
|
|||
statusLoading,
|
||||
topupInfo,
|
||||
onOpenHistory,
|
||||
enableAlipayTopUp,
|
||||
enableWechatPayTopUp,
|
||||
enableWaffoTopUp,
|
||||
waffoTopUp,
|
||||
waffoPayMethods,
|
||||
|
|
@ -213,13 +215,15 @@ const RechargeCard = ({
|
|||
) : enableOnlineTopUp ||
|
||||
enableStripeTopUp ||
|
||||
enableCreemTopUp ||
|
||||
enableAlipayTopUp ||
|
||||
enableWechatPayTopUp ||
|
||||
enableWaffoTopUp ? (
|
||||
<Form
|
||||
getFormApi={(api) => (onlineFormApiRef.current = api)}
|
||||
initValues={{ topUpCount: topUpCount }}
|
||||
>
|
||||
<div className='space-y-6'>
|
||||
{(enableOnlineTopUp || enableStripeTopUp || enableWaffoTopUp) && (
|
||||
{(enableOnlineTopUp || enableStripeTopUp || enableWaffoTopUp || enableAlipayTopUp || enableWechatPayTopUp) && (
|
||||
<Row gutter={12}>
|
||||
<Col xs={24} sm={24} md={24} lg={10} xl={10}>
|
||||
<Form.InputNumber
|
||||
|
|
@ -228,7 +232,9 @@ const RechargeCard = ({
|
|||
disabled={
|
||||
!enableOnlineTopUp &&
|
||||
!enableStripeTopUp &&
|
||||
!enableWaffoTopUp
|
||||
!enableWaffoTopUp &&
|
||||
!enableAlipayTopUp &&
|
||||
!enableWechatPayTopUp
|
||||
}
|
||||
placeholder={
|
||||
t('充值数量,最低 ') + renderTopUpCount(minTopUp)
|
||||
|
|
@ -282,26 +288,30 @@ const RechargeCard = ({
|
|||
/>
|
||||
</Col>
|
||||
{payMethods &&
|
||||
payMethods.filter((m) => m.type !== 'waffo').length > 0 && (
|
||||
payMethods.filter((m) => m.type !== 'waffo' && m.type !== 'custom1').length > 0 && (
|
||||
<Col xs={24} sm={24} md={24} lg={14} xl={14}>
|
||||
<Form.Slot label={t('选择支付方式')}>
|
||||
<Space wrap>
|
||||
{payMethods
|
||||
.filter((m) => m.type !== 'waffo')
|
||||
.filter((m) => m.type !== 'waffo' && m.type !== 'custom1')
|
||||
.map((payMethod) => {
|
||||
const minTopupVal =
|
||||
Number(payMethod.min_topup) || 0;
|
||||
const isStripe = payMethod.type === 'stripe';
|
||||
const isAlipay = payMethod.type === 'alipay';
|
||||
const isWechat = payMethod.type === 'wxpay';
|
||||
const disabled =
|
||||
(!enableOnlineTopUp && !isStripe) ||
|
||||
(!enableOnlineTopUp && !isStripe && !isAlipay && !isWechat) ||
|
||||
(!enableStripeTopUp && isStripe) ||
|
||||
(!enableAlipayTopUp && isAlipay) ||
|
||||
(!enableWechatPayTopUp && isWechat) ||
|
||||
minTopupVal > Number(topUpCount || 0);
|
||||
|
||||
const buttonEl = (
|
||||
<Button
|
||||
key={payMethod.type}
|
||||
theme='outline'
|
||||
type='tertiary'
|
||||
theme={payWay === payMethod.type ? 'solid' : 'outline'}
|
||||
type={payWay === payMethod.type ? 'primary' : 'tertiary'}
|
||||
onClick={() => preTopUp(payMethod.type)}
|
||||
disabled={disabled}
|
||||
loading={
|
||||
|
|
@ -310,11 +320,11 @@ const RechargeCard = ({
|
|||
}
|
||||
icon={
|
||||
payMethod.type === 'alipay' ? (
|
||||
<SiAlipay size={18} color='#1677FF' />
|
||||
<SiAlipay size={18} color={payWay === payMethod.type ? 'white' : '#1677FF'} />
|
||||
) : payMethod.type === 'wxpay' ? (
|
||||
<SiWechat size={18} color='#07C160' />
|
||||
<SiWechat size={18} color={payWay === payMethod.type ? 'white' : '#07C160'} />
|
||||
) : payMethod.type === 'stripe' ? (
|
||||
<SiStripe size={18} color='#635BFF' />
|
||||
<SiStripe size={18} color={payWay === payMethod.type ? 'white' : '#635BFF'} />
|
||||
) : (
|
||||
<CreditCard
|
||||
size={18}
|
||||
|
|
@ -356,7 +366,7 @@ const RechargeCard = ({
|
|||
</Row>
|
||||
)}
|
||||
|
||||
{(enableOnlineTopUp || enableStripeTopUp || enableWaffoTopUp) && (
|
||||
{(enableOnlineTopUp || enableStripeTopUp || enableWaffoTopUp || enableAlipayTopUp || enableWechatPayTopUp) && (
|
||||
<Form.Slot
|
||||
label={
|
||||
<div className='flex items-center gap-2'>
|
||||
|
|
|
|||
|
|
@ -527,22 +527,26 @@ const TopUp = () => {
|
|||
const enableStripeTopUp = data.enable_stripe_topup || false;
|
||||
const enableOnlineTopUp = data.enable_online_topup || false;
|
||||
const enableCreemTopUp = data.enable_creem_topup || false;
|
||||
const enableWaffoTopUp = data.enable_waffo_topup || false;
|
||||
const enableAlipayTopUp = data.enable_alipay_topup || false;
|
||||
const enableWechatPayTopUp = data.enable_wechatpay_topup || false;
|
||||
const minTopUpValue = enableOnlineTopUp
|
||||
? data.min_topup
|
||||
: enableStripeTopUp
|
||||
? data.stripe_min_topup
|
||||
: data.enable_waffo_topup
|
||||
: enableWaffoTopUp
|
||||
? data.waffo_min_topup
|
||||
: enableAlipayTopUp
|
||||
? data.alipay_min_topup
|
||||
: enableWechatPayTopUp
|
||||
? data.wechatpay_min_topup
|
||||
: 1;
|
||||
setEnableOnlineTopUp(enableOnlineTopUp);
|
||||
setEnableStripeTopUp(enableStripeTopUp);
|
||||
setEnableCreemTopUp(enableCreemTopUp);
|
||||
const enableWaffoTopUp = data.enable_waffo_topup || false;
|
||||
const enableAlipayTopUp = data.enable_alipay_topup || false;
|
||||
setEnableAlipayTopUp(enableAlipayTopUp);
|
||||
const enableWechatPayTopUp = data.enable_wechatpay_topup || false;
|
||||
setEnableWechatPayTopUp(enableWechatPayTopUp);
|
||||
setEnableWaffoTopUp(enableWaffoTopUp);
|
||||
setEnableAlipayTopUp(enableAlipayTopUp);
|
||||
setEnableWechatPayTopUp(enableWechatPayTopUp);
|
||||
setWaffoPayMethods(data.waffo_pay_methods || []);
|
||||
setWaffoMinTopUp(data.waffo_min_topup || 1);
|
||||
setMinTopUp(minTopUpValue);
|
||||
|
|
@ -810,9 +814,13 @@ const TopUp = () => {
|
|||
}
|
||||
const minTopupVal = Number(method.min_topup) || 0;
|
||||
const isStripe = method.type === 'stripe';
|
||||
const isAlipay = method.type === 'alipay';
|
||||
const isWechat = method.type === 'wxpay';
|
||||
const disabled =
|
||||
(!enableOnlineTopUp && !isStripe) ||
|
||||
(!enableOnlineTopUp && !isStripe && !isAlipay && !isWechat) ||
|
||||
(!enableStripeTopUp && isStripe) ||
|
||||
(!enableAlipayTopUp && isAlipay) ||
|
||||
(!enableWechatPayTopUp && isWechat) ||
|
||||
minTopupVal > Number(count || 0);
|
||||
return !disabled;
|
||||
});
|
||||
|
|
@ -823,7 +831,7 @@ const TopUp = () => {
|
|||
selectPresetAmount(preset);
|
||||
const enabledMethods = getEnabledEpayMethods(preset.value);
|
||||
if (enabledMethods.length === 0) {
|
||||
showError(t('当前额度暂无可用支付方式'));
|
||||
showError(t('暂无可用的支付方式,请联系管理员配置'));
|
||||
return;
|
||||
}
|
||||
if (enabledMethods.length === 1) {
|
||||
|
|
@ -880,6 +888,8 @@ const TopUp = () => {
|
|||
payMethods={payMethods}
|
||||
enableOnlineTopUp={enableOnlineTopUp}
|
||||
enableStripeTopUp={enableStripeTopUp}
|
||||
enableAlipayTopUp={enableAlipayTopUp}
|
||||
enableWechatPayTopUp={enableWechatPayTopUp}
|
||||
onSelect={handlePaymentMethodSelect}
|
||||
paymentLoading={paymentLoading}
|
||||
payWay={payWay}
|
||||
|
|
@ -994,6 +1004,8 @@ const TopUp = () => {
|
|||
enableWaffoTopUp={enableWaffoTopUp}
|
||||
waffoTopUp={waffoTopUp}
|
||||
waffoPayMethods={waffoPayMethods}
|
||||
enableAlipayTopUp={enableAlipayTopUp}
|
||||
enableWechatPayTopUp={enableWechatPayTopUp}
|
||||
presetAmounts={presetAmounts}
|
||||
selectedPreset={selectedPreset}
|
||||
selectPresetAmount={selectPresetAmount}
|
||||
|
|
|
|||
|
|
@ -14,11 +14,13 @@ const PaymentMethodSelectModal = ({
|
|||
payMethods = [],
|
||||
enableOnlineTopUp,
|
||||
enableStripeTopUp,
|
||||
enableAlipayTopUp,
|
||||
enableWechatPayTopUp,
|
||||
onSelect,
|
||||
paymentLoading,
|
||||
payWay,
|
||||
}) => {
|
||||
const epayMethods = payMethods.filter((m) => m.type !== 'waffo');
|
||||
const epayMethods = payMethods.filter((m) => m.type !== 'waffo' && m.type !== 'custom1');
|
||||
|
||||
const renderPayIcon = (payMethod) => {
|
||||
if (payMethod.type === 'alipay') {
|
||||
|
|
@ -61,9 +63,13 @@ const PaymentMethodSelectModal = ({
|
|||
{epayMethods.map((payMethod) => {
|
||||
const minTopupVal = Number(payMethod.min_topup) || 0;
|
||||
const isStripe = payMethod.type === 'stripe';
|
||||
const isAlipay = payMethod.type === 'alipay';
|
||||
const isWechat = payMethod.type === 'wxpay';
|
||||
const disabled =
|
||||
(!enableOnlineTopUp && !isStripe) ||
|
||||
(!enableOnlineTopUp && !isStripe && !isAlipay && !isWechat) ||
|
||||
(!enableStripeTopUp && isStripe) ||
|
||||
(!enableAlipayTopUp && isAlipay) ||
|
||||
(!enableWechatPayTopUp && isWechat) ||
|
||||
minTopupVal > Number(topUpCount || 0);
|
||||
|
||||
const buttonEl = (
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ For commercial licensing, please contact support@quantumnous.com
|
|||
*/
|
||||
|
||||
import React, { useCallback, useLayoutEffect, useRef, useState } from 'react';
|
||||
import { Button, Form, Row, Col, Typography, Spin, TextArea } from '@douyinfe/semi-ui';
|
||||
import { Button, Form, Row, Col, Typography, Spin, TextArea, Checkbox } from '@douyinfe/semi-ui';
|
||||
const { Text } = Typography;
|
||||
import {
|
||||
API,
|
||||
|
|
@ -67,6 +67,12 @@ function getDefaultYipayReturnHint(serverAddress) {
|
|||
*/
|
||||
function normalizeOnlinePayProvider(provider) {
|
||||
const value = (provider || '').toLowerCase();
|
||||
if (value === 'alipay') {
|
||||
return 'alipay';
|
||||
}
|
||||
if (value === 'wechatpay' || value === 'wxpay') {
|
||||
return 'wechatpay';
|
||||
}
|
||||
if (value === 'yipay' || value === 'jeepay') {
|
||||
return 'yipay';
|
||||
}
|
||||
|
|
@ -96,6 +102,16 @@ function buildFormModelFromOptions(opts) {
|
|||
YipayReturnUrl: opts.YipayReturnUrl || '',
|
||||
YipayChannelExtra: String(opts.YipayChannelExtra ?? ''),
|
||||
YipayRequestURL: yipayReq,
|
||||
AlipayEnabled: opts.AlipayEnabled === true || opts.AlipayEnabled === 'true',
|
||||
AlipayAppId: opts.AlipayAppId || '',
|
||||
AlipayPrivateKey: opts.AlipayPrivateKey || '',
|
||||
AlipayPublicKey: opts.AlipayPublicKey || '',
|
||||
WechatPayEnabled: opts.WechatPayEnabled === true || opts.WechatPayEnabled === 'true',
|
||||
WechatPayAppId: opts.WechatPayAppId || '',
|
||||
WechatPayMchId: opts.WechatPayMchId || '',
|
||||
WechatPayApiV3Key: opts.WechatPayApiV3Key || '',
|
||||
EpayEnabled: opts.EpayEnabled === true || opts.EpayEnabled === 'true',
|
||||
YipayEnabled: opts.YipayEnabled === true || opts.YipayEnabled === 'true',
|
||||
Price: opts.Price !== undefined ? parseFloat(String(opts.Price)) : 7.3,
|
||||
MinTopUp:
|
||||
opts.MinTopUp !== undefined ? parseFloat(String(opts.MinTopUp)) : 1,
|
||||
|
|
@ -149,6 +165,16 @@ export default function SettingsPaymentGateway(props) {
|
|||
YipayReturnUrl: '',
|
||||
YipayChannelExtra: '',
|
||||
YipayRequestURL: '',
|
||||
AlipayEnabled: false,
|
||||
AlipayAppId: '',
|
||||
AlipayPrivateKey: '',
|
||||
AlipayPublicKey: '',
|
||||
WechatPayEnabled: false,
|
||||
WechatPayAppId: '',
|
||||
WechatPayMchId: '',
|
||||
WechatPayApiV3Key: '',
|
||||
EpayEnabled: false,
|
||||
YipayEnabled: false,
|
||||
Price: 7.3,
|
||||
MinTopUp: 1,
|
||||
TopupGroupRatio: '',
|
||||
|
|
@ -289,6 +315,26 @@ export default function SettingsPaymentGateway(props) {
|
|||
}
|
||||
}
|
||||
|
||||
if (currentProvider === 'alipay') {
|
||||
if (!inputs.AlipayAppId?.trim()) {
|
||||
showError(t('支付宝模式下必须填写应用ID'));
|
||||
return;
|
||||
}
|
||||
if (!inputs.AlipayPrivateKey?.trim()) {
|
||||
showError(t('支付宝模式下必须填写私钥'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (currentProvider === 'wechatpay') {
|
||||
if (!inputs.WechatPayAppId?.trim()) {
|
||||
showError(t('微信支付模式下必须填写应用ID'));
|
||||
return;
|
||||
}
|
||||
if (!inputs.WechatPayMchId?.trim()) {
|
||||
showError(t('微信支付模式下必须填写商户号'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (currentProvider === 'yipay') {
|
||||
if (!inputs.YipayMchNo?.trim()) {
|
||||
showError(t('Yipay 模式下必须填写商户号'));
|
||||
|
|
@ -328,50 +374,62 @@ export default function SettingsPaymentGateway(props) {
|
|||
},
|
||||
];
|
||||
|
||||
if (currentProvider === 'epay') {
|
||||
// Alipay options
|
||||
options.push({ key: 'AlipayEnabled', value: inputs.AlipayEnabled ? 'true' : 'false' });
|
||||
options.push({ key: 'AlipayAppId', value: inputs.AlipayAppId?.trim() || '' });
|
||||
options.push({ key: 'AlipayPrivateKey', value: inputs.AlipayPrivateKey || '' });
|
||||
options.push({ key: 'AlipayPublicKey', value: inputs.AlipayPublicKey?.trim() || '' });
|
||||
|
||||
// Epay/Yipay options
|
||||
options.push({ key: 'EpayEnabled', value: inputs.EpayEnabled ? 'true' : 'false' });
|
||||
options.push({ key: 'YipayEnabled', value: inputs.YipayEnabled ? 'true' : 'false' });
|
||||
|
||||
// WeChat Pay options
|
||||
options.push({ key: 'WechatPayEnabled', value: inputs.WechatPayEnabled ? 'true' : 'false' });
|
||||
options.push({ key: 'WechatPayAppId', value: inputs.WechatPayAppId?.trim() || '' });
|
||||
options.push({ key: 'WechatPayMchId', value: inputs.WechatPayMchId?.trim() || '' });
|
||||
options.push({ key: 'WechatPayApiV3Key', value: inputs.WechatPayApiV3Key || '' });
|
||||
|
||||
options.push({
|
||||
key: 'PayAddress',
|
||||
value: removeTrailingSlash(inputs.PayAddress || ''),
|
||||
});
|
||||
}
|
||||
if (currentProvider === 'yipay') {
|
||||
|
||||
const gatewayBase = removeTrailingSlash(
|
||||
(inputs.YipayRequestURL || '').trim(),
|
||||
);
|
||||
options.push({ key: 'YipayRequestURL', value: gatewayBase });
|
||||
options.push({ key: 'PayAddress', value: gatewayBase });
|
||||
}
|
||||
|
||||
if (currentProvider === 'epay' && inputs.EpayId !== '') {
|
||||
|
||||
if (inputs.EpayId !== '') {
|
||||
options.push({ key: 'EpayId', value: inputs.EpayId });
|
||||
}
|
||||
if (currentProvider === 'yipay' && inputs.YipayMchNo !== '') {
|
||||
if (inputs.YipayMchNo !== '') {
|
||||
options.push({ key: 'YipayMchNo', value: inputs.YipayMchNo.trim() });
|
||||
}
|
||||
if (
|
||||
currentProvider === 'epay' &&
|
||||
inputs.EpayKey !== undefined &&
|
||||
inputs.EpayKey !== ''
|
||||
) {
|
||||
options.push({ key: 'EpayKey', value: inputs.EpayKey });
|
||||
}
|
||||
if (currentProvider === 'yipay' && inputs.YipayAppId !== '') {
|
||||
if (inputs.YipayAppId !== '') {
|
||||
options.push({ key: 'YipayAppId', value: inputs.YipayAppId.trim() });
|
||||
}
|
||||
if (currentProvider === 'yipay' && inputs.YipayNotifyUrl !== '') {
|
||||
if (inputs.YipayNotifyUrl !== '') {
|
||||
options.push({
|
||||
key: 'YipayNotifyUrl',
|
||||
value: inputs.YipayNotifyUrl.trim(),
|
||||
});
|
||||
}
|
||||
if (currentProvider === 'yipay' && inputs.YipayReturnUrl !== '') {
|
||||
if (inputs.YipayReturnUrl !== '') {
|
||||
options.push({
|
||||
key: 'YipayReturnUrl',
|
||||
value: inputs.YipayReturnUrl.trim(),
|
||||
});
|
||||
}
|
||||
if (
|
||||
currentProvider === 'yipay' &&
|
||||
(inputs.YipayChannelExtra ?? '').trim() !==
|
||||
(originInputs.YipayChannelExtra ?? '').trim()
|
||||
) {
|
||||
|
|
@ -381,7 +439,6 @@ export default function SettingsPaymentGateway(props) {
|
|||
});
|
||||
}
|
||||
if (
|
||||
currentProvider === 'yipay' &&
|
||||
inputs.YipayAppSecret !== undefined &&
|
||||
inputs.YipayAppSecret.trim() !== '' &&
|
||||
inputs.YipayAppSecret !== originInputs.YipayAppSecret
|
||||
|
|
@ -459,198 +516,161 @@ export default function SettingsPaymentGateway(props) {
|
|||
>
|
||||
<Form.Section text={t('支付设置')}>
|
||||
<Text>
|
||||
{t(
|
||||
'(当前支持易支付/Yipay 配置,默认使用上方服务器地址作为回调地址!)',
|
||||
)}
|
||||
{t('支持支付宝、微信支付、易支付 / Yipay 等在线支付渠道配置')}
|
||||
</Text>
|
||||
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 24, xl: 24, xxl: 24 }}>
|
||||
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
|
||||
<Form.Select
|
||||
field='OnlinePayProvider'
|
||||
field="OnlinePayProvider"
|
||||
label={t('在线支付通道')}
|
||||
optionList={[
|
||||
{ label: t('支付宝'), value: 'alipay' },
|
||||
{ label: t('微信支付'), value: 'wechatpay' },
|
||||
{ label: t('易支付'), value: 'epay' },
|
||||
{ label: t('Yipay'), value: 'yipay' },
|
||||
]}
|
||||
/>
|
||||
</Col>
|
||||
<Col
|
||||
xs={24}
|
||||
sm={24}
|
||||
md={8}
|
||||
lg={8}
|
||||
xl={8}
|
||||
xs={24} sm={24} md={8} lg={8} xl={8}
|
||||
style={{
|
||||
display: currentProvider === 'epay' ? 'block' : 'none',
|
||||
display: currentProvider === 'alipay' ? 'flex' : 'none',
|
||||
alignItems: 'center',
|
||||
paddingTop: 30,
|
||||
}}
|
||||
>
|
||||
<Checkbox
|
||||
checked={inputs.AlipayEnabled}
|
||||
onChange={(e) => { const val = e.target.checked; setInputs((prev) => ({ ...prev, AlipayEnabled: val })); }}
|
||||
>
|
||||
{t('启用支付宝支付')}
|
||||
</Checkbox>
|
||||
</Col>
|
||||
<Col
|
||||
xs={24} sm={24} md={8} lg={8} xl={8}
|
||||
style={{
|
||||
display: currentProvider === 'wechatpay' ? 'flex' : 'none',
|
||||
alignItems: 'center',
|
||||
paddingTop: 30,
|
||||
}}
|
||||
>
|
||||
<Checkbox
|
||||
checked={inputs.WechatPayEnabled}
|
||||
onChange={(e) => { const val = e.target.checked; setInputs((prev) => ({ ...prev, WechatPayEnabled: val })); }}
|
||||
>
|
||||
{t('启用微信支付')}
|
||||
</Checkbox>
|
||||
</Col>
|
||||
</Row><Row gutter={{ xs: 8, sm: 16, md: 24, lg: 24, xl: 24, xxl: 24 }}>
|
||||
|
||||
<Col
|
||||
xs={24} sm={24} md={8} lg={8} xl={8}
|
||||
style={{
|
||||
display: currentProvider === 'epay' ? 'flex' : 'none',
|
||||
alignItems: 'center',
|
||||
paddingTop: 30,
|
||||
}}
|
||||
>
|
||||
<Checkbox
|
||||
checked={inputs.EpayEnabled}
|
||||
onChange={(e) => { const val = e.target.checked; setInputs((prev) => ({ ...prev, EpayEnabled: val })); }}
|
||||
>
|
||||
{t('启用易支付')}
|
||||
</Checkbox>
|
||||
</Col>
|
||||
<Col
|
||||
xs={24} sm={24} md={8} lg={8} xl={8}
|
||||
style={{
|
||||
display: currentProvider === 'yipay' ? 'flex' : 'none',
|
||||
alignItems: 'center',
|
||||
paddingTop: 30,
|
||||
}}
|
||||
>
|
||||
<Checkbox
|
||||
checked={inputs.YipayEnabled}
|
||||
onChange={(e) => { const val = e.target.checked; setInputs((prev) => ({ ...prev, YipayEnabled: val })); }}
|
||||
>
|
||||
{t('启用 Yipay')}
|
||||
</Checkbox>
|
||||
</Col>
|
||||
</Row><Row
|
||||
gutter={{ xs: 8, sm: 16, md: 24, lg: 24, xl: 24, xxl: 24 }}
|
||||
style={{ marginTop: 8, display: currentProvider === 'alipay' ? 'flex' : 'none' }}
|
||||
>
|
||||
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
|
||||
<Form.Input field="AlipayAppId" label={t('支付宝应用ID')} placeholder={t('请填写支付宝应用ID')} />
|
||||
</Col>
|
||||
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
|
||||
<Form.Input field="AlipayPrivateKey" label={t('支付宝私钥')} placeholder={t('请填写支付宝私钥')} type="password" />
|
||||
</Col>
|
||||
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
|
||||
<Form.Input field="AlipayPublicKey" label={t('支付宝公钥')} placeholder={t('请填写支付宝公钥')} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row
|
||||
gutter={{ xs: 8, sm: 16, md: 24, lg: 24, xl: 24, xxl: 24 }}
|
||||
style={{ marginTop: 8, display: currentProvider === 'wechatpay' ? 'flex' : 'none' }}
|
||||
>
|
||||
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
|
||||
<Form.Input field="WechatPayAppId" label={t('微信支付应用ID')} placeholder={t('请填写微信支付应用ID')} />
|
||||
</Col>
|
||||
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
|
||||
<Form.Input field="WechatPayMchId" label={t('微信支付商户号')} placeholder={t('请填写微信支付商户号')} />
|
||||
</Col>
|
||||
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
|
||||
<Form.Input field="WechatPayApiV3Key" label={t('微信支付 API V3 密钥')} placeholder={t('请填写 API V3 密钥')} type="password" />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row
|
||||
gutter={{ xs: 8, sm: 16, md: 24, lg: 24, xl: 24, xxl: 24 }}
|
||||
style={{ marginTop: 8, display: currentProvider === 'epay' ? 'flex' : 'none' }}
|
||||
>
|
||||
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
|
||||
<Form.Input field="PayAddress" label={t('支付地址')} placeholder={t('例如:https://yourdomain.com')} />
|
||||
</Col>
|
||||
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
|
||||
<Form.Input field="EpayId" label={t('易支付商户号')} placeholder={t('例如:0001')} />
|
||||
</Col>
|
||||
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
|
||||
<Form.Input field="EpayKey" label={t('易支付商户密钥')} placeholder={t('敏感信息不会发送到前端显示')} type="password" />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row
|
||||
gutter={{ xs: 8, sm: 16, md: 24, lg: 24, xl: 24, xxl: 24 }}
|
||||
style={{ marginTop: 8, display: currentProvider === 'yipay' ? 'flex' : 'none' }}
|
||||
>
|
||||
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
|
||||
<Form.Input
|
||||
field='PayAddress'
|
||||
field="YipayRequestURL"
|
||||
label={t('支付地址')}
|
||||
placeholder={t('例如:https://yourdomain.com')}
|
||||
placeholder={t('例如:https://pay.xxx.com(与易支付网关根地址相同)')}
|
||||
extraText={t('对应配置项 YipayRequestURL;保存时会同步写入 PayAddress,供服务端与易支付字段兼容。')}
|
||||
/>
|
||||
</Col>
|
||||
<Col
|
||||
xs={24}
|
||||
sm={24}
|
||||
md={8}
|
||||
lg={8}
|
||||
xl={8}
|
||||
style={{
|
||||
display: currentProvider === 'yipay' ? 'block' : 'none',
|
||||
}}
|
||||
>
|
||||
<Form.Input
|
||||
field='YipayRequestURL'
|
||||
label={t('支付地址')}
|
||||
placeholder={t(
|
||||
'例如:https://pay.xxx.com(与易支付网关根地址相同)',
|
||||
)}
|
||||
extraText={t(
|
||||
'对应配置项 YipayRequestURL;保存时会同步写入 PayAddress,供服务端与易支付字段兼容。',
|
||||
)}
|
||||
/>
|
||||
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
|
||||
<Form.Input field="YipayMchNo" label={t('Yipay 商户号(可选覆盖)')} placeholder={t('例如:M1691xxxx')} />
|
||||
</Col>
|
||||
<Col
|
||||
xs={24}
|
||||
sm={24}
|
||||
md={8}
|
||||
lg={8}
|
||||
xl={8}
|
||||
style={{
|
||||
display: currentProvider === 'epay' ? 'block' : 'none',
|
||||
}}
|
||||
>
|
||||
<Form.Input
|
||||
field='EpayId'
|
||||
label={t('易支付商户号')}
|
||||
placeholder={t('例如:0001')}
|
||||
/>
|
||||
</Col>
|
||||
<Col
|
||||
xs={24}
|
||||
sm={24}
|
||||
md={8}
|
||||
lg={8}
|
||||
xl={8}
|
||||
style={{
|
||||
display: currentProvider === 'epay' ? 'block' : 'none',
|
||||
}}
|
||||
>
|
||||
<Form.Input
|
||||
field='EpayKey'
|
||||
label={t('易支付商户密钥')}
|
||||
placeholder={t('敏感信息不会发送到前端显示')}
|
||||
type='password'
|
||||
/>
|
||||
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
|
||||
<Form.Input field="YipayAppId" label={t('Yipay 应用ID')} placeholder={t('例如:62b2f8f6xxxxxx')} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row
|
||||
gutter={{ xs: 8, sm: 16, md: 24, lg: 24, xl: 24, xxl: 24 }}
|
||||
style={{
|
||||
marginTop: 16,
|
||||
display: currentProvider === 'yipay' ? 'flex' : 'none',
|
||||
}}
|
||||
style={{ marginTop: 16, display: currentProvider === 'yipay' ? 'flex' : 'none' }}
|
||||
>
|
||||
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
|
||||
<Form.Input
|
||||
field='YipayMchNo'
|
||||
label={t('Yipay 商户号(可选覆盖)')}
|
||||
placeholder={t('例如:M1691xxxx')}
|
||||
/>
|
||||
<Form.Input field="YipayAppSecret" label={t('Yipay AppSecret')} placeholder={t('用于 MD5 签名的密钥(后端脱敏回显;修改后保存才会更新)')} autoComplete="off" />
|
||||
</Col>
|
||||
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
|
||||
<Form.Input
|
||||
field='YipayAppId'
|
||||
label={t('Yipay 应用ID')}
|
||||
placeholder={t('例如:62b2f8f6xxxxxx')}
|
||||
/>
|
||||
<Form.Input field="YipayNotifyUrl" label={t('Yipay 异步通知地址')} placeholder={t('可留空,留空则使用下方"回调地址"或服务器地址拼接默认路径')} />
|
||||
</Col>
|
||||
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
|
||||
<Form.Input
|
||||
field='YipayAppSecret'
|
||||
label={t('Yipay AppSecret')}
|
||||
placeholder={t(
|
||||
'用于 MD5 签名的密钥(后端脱敏回显;修改后保存才会更新)',
|
||||
)}
|
||||
autoComplete='off'
|
||||
/>
|
||||
<Form.Input field="YipayReturnUrl" label={t('Yipay 同步通知地址')} placeholder={t('例如:https://yourdomain.com/console/log')} />
|
||||
</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='CustomCallbackAddress'
|
||||
label={t('回调地址')}
|
||||
placeholder={t('例如:https://yourdomain.com')}
|
||||
/>
|
||||
</Col>
|
||||
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
|
||||
<Form.InputNumber
|
||||
field='Price'
|
||||
precision={2}
|
||||
label={t('充值价格(x元/美金)')}
|
||||
placeholder={t('例如:7,就是7元/美金')}
|
||||
/>
|
||||
</Col>
|
||||
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
|
||||
<Form.InputNumber
|
||||
field='MinTopUp'
|
||||
label={t('最低充值美元数量')}
|
||||
placeholder={t('例如:2,就是最低充值2$')}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row
|
||||
gutter={{ xs: 8, sm: 16, md: 24, lg: 24, xl: 24, xxl: 24 }}
|
||||
style={{
|
||||
marginTop: 16,
|
||||
display: currentProvider === 'yipay' ? 'flex' : 'none',
|
||||
}}
|
||||
>
|
||||
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
|
||||
<Form.Input
|
||||
field='YipayNotifyUrl'
|
||||
label={t('Yipay 异步通知地址')}
|
||||
placeholder={t(
|
||||
'可留空,留空则使用下方「回调地址」或服务器地址拼接默认路径',
|
||||
)}
|
||||
extraText={(() => {
|
||||
const hint = getDefaultYipayNotifyHint(
|
||||
props.options.ServerAddress,
|
||||
props.options.CustomCallbackAddress,
|
||||
);
|
||||
return hint
|
||||
? `默认:${hint}(留空时与后端异步通知规则一致)`
|
||||
: '请先配置「服务器地址」或「回调地址」以预览默认异步通知 URL';
|
||||
})()}
|
||||
/>
|
||||
</Col>
|
||||
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
|
||||
<Form.Input
|
||||
field='YipayReturnUrl'
|
||||
label={t('Yipay 同步通知地址')}
|
||||
placeholder={t('例如:https://yourdomain.com/console/log')}
|
||||
extraText={(() => {
|
||||
const hint = getDefaultYipayReturnHint(
|
||||
props.options.ServerAddress,
|
||||
);
|
||||
return hint
|
||||
? `默认:${hint}(留空时使用)`
|
||||
: '请先配置「服务器地址」以预览默认同步跳转 URL';
|
||||
})()}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row
|
||||
gutter={{ xs: 8, sm: 16, md: 24, lg: 24, xl: 24, xxl: 24 }}
|
||||
style={{
|
||||
marginTop: 8,
|
||||
display: currentProvider === 'yipay' ? 'flex' : 'none',
|
||||
}}
|
||||
style={{ marginTop: 8, display: currentProvider === 'yipay' ? 'flex' : 'none' }}
|
||||
>
|
||||
<Col span={24}>
|
||||
<div style={{ marginBottom: 8 }}>
|
||||
|
|
@ -659,77 +679,39 @@ export default function SettingsPaymentGateway(props) {
|
|||
<TextArea
|
||||
value={inputs.YipayChannelExtra}
|
||||
onChange={handleYipayChannelExtraChange}
|
||||
placeholder={'{"payDataType":"payUrl"}'}
|
||||
placeholder='{"payDataType":"payUrl"}'
|
||||
rows={1}
|
||||
autoComplete='off'
|
||||
style={{
|
||||
width: '100%',
|
||||
fontFamily: 'monospace',
|
||||
fontSize: 12,
|
||||
}}
|
||||
autoComplete="off"
|
||||
style={{ width: "100%", fontFamily: "monospace", fontSize: 12 }}
|
||||
/>
|
||||
<Text
|
||||
type='tertiary'
|
||||
size='small'
|
||||
style={{ marginTop: 8, display: 'block' }}
|
||||
>
|
||||
{t(
|
||||
'可选。Jeepay channelExtra(JSON)。留空时:一般 _PC 会附带 payDataType=payUrl;PP_PC 会附带 payDataType 与 cancelUrl(与 returnUrl 同源,见 yiPay PPPcOrderRQ)。可在此覆盖 cancelUrl 等。',
|
||||
)}
|
||||
<Text type="tertiary" size="small" style={{ marginTop: 8, display: "block" }}>
|
||||
{t('可选。Jeepay channelExtra(JSON)。留空时:一般 _PC 会附带 payDataType=payUrl;PP_PC 会附带 payDataType 与 cancelUrl(与 returnUrl 同源,见 yiPay PPPcOrderRQ)。可在此覆盖 cancelUrl 等。')}
|
||||
</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
<Form.TextArea
|
||||
field='TopupGroupRatio'
|
||||
label={t('充值分组倍率')}
|
||||
placeholder={t('为一个 JSON 文本,键为组名称,值为倍率')}
|
||||
autosize
|
||||
/>
|
||||
<Form.TextArea
|
||||
field='PayMethods'
|
||||
label={t('充值方式设置')}
|
||||
placeholder={t('为一个 JSON 文本')}
|
||||
autosize
|
||||
/>
|
||||
|
||||
<Row
|
||||
gutter={{ xs: 8, sm: 16, md: 24, lg: 24, xl: 24, xxl: 24 }}
|
||||
style={{ marginTop: 16 }}
|
||||
>
|
||||
<Col span={24}>
|
||||
<Form.TextArea
|
||||
field='AmountOptions'
|
||||
label={t('自定义充值数量选项')}
|
||||
placeholder={t(
|
||||
'为一个 JSON 数组,例如:[10, 20, 50, 100, 200, 500]',
|
||||
)}
|
||||
autosize
|
||||
extraText={t(
|
||||
'设置用户可选择的充值数量选项,例如:[10, 20, 50, 100, 200, 500]',
|
||||
)}
|
||||
/>
|
||||
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 24, xl: 24, xxl: 24 }} style={{ marginTop: 8 }}>
|
||||
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
|
||||
<Form.Input field="CustomCallbackAddress" label={t('回调地址')} placeholder={t('例如:https://yourdomain.com')} />
|
||||
</Col>
|
||||
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
|
||||
<Form.InputNumber field="Price" precision={2} label={t('充值价格(x元/美金)')} placeholder={t('例如:7,就是7元/美金')} />
|
||||
</Col>
|
||||
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
|
||||
<Form.InputNumber field="MinTopUp" label={t('最低充值美元数量')} placeholder={t('例如:2,就是最低充值2$')} />
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Row
|
||||
gutter={{ xs: 8, sm: 16, md: 24, lg: 24, xl: 24, xxl: 24 }}
|
||||
style={{ marginTop: 16 }}
|
||||
>
|
||||
<Form.TextArea field="TopupGroupRatio" label={t('充值分组倍率')} placeholder={t('为一个 JSON 文本,键为组名称,值为倍率')} autosize />
|
||||
<Form.TextArea field="PayMethods" label={t('充值方式设置')} placeholder={t('为一个 JSON 文本')} autosize />
|
||||
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 24, xl: 24, xxl: 24 }} style={{ marginTop: 16 }}>
|
||||
<Col span={24}>
|
||||
<Form.TextArea
|
||||
field='AmountDiscount'
|
||||
label={t('充值金额折扣配置')}
|
||||
placeholder={t(
|
||||
'为一个 JSON 对象,例如:{"100": 0.95, "200": 0.9, "500": 0.85}',
|
||||
)}
|
||||
autosize
|
||||
extraText={t(
|
||||
'设置不同充值金额对应的折扣,键为充值金额,值为折扣率,例如:{"100": 0.95, "200": 0.9, "500": 0.85}',
|
||||
)}
|
||||
/>
|
||||
<Form.TextArea field="AmountOptions" label={t('自定义充值数量选项')} placeholder={t('为一个 JSON 数组,例如:[10, 20, 50, 100, 200, 500]')} autosize extraText={t('设置用户可选择的充值数量选项,例如:[10, 20, 50, 100, 200, 500]')} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 24, xl: 24, xxl: 24 }} style={{ marginTop: 16 }}>
|
||||
<Col span={24}>
|
||||
<Form.TextArea field="AmountDiscount" label={t('充值金额折扣配置')} placeholder={t('为一个 JSON 对象,例如:{"100": 0.95, "200": 0.9, "500": 0.85}')} autosize extraText={t('设置不同充值金额对应的折扣,键为充值金额,值为折扣率,例如:{"100": 0.95, "200": 0.9, "500": 0.85}')} />
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Button onClick={submitPayAddress}>{t('更新支付设置')}</Button>
|
||||
</Form.Section>
|
||||
</Form>
|
||||
|
|
|
|||
Loading…
Reference in New Issue