diff --git a/web/src/components/settings/PaymentSetting.js b/web/src/components/settings/PaymentSetting.js new file mode 100644 index 00000000..91a40a2b --- /dev/null +++ b/web/src/components/settings/PaymentSetting.js @@ -0,0 +1,88 @@ +import React, { useEffect, useState } from 'react'; +import { Card, Spin } from '@douyinfe/semi-ui'; +import SettingsGeneralPayment from '../../pages/Setting/Payment/SettingsGeneralPayment.js'; +import SettingsPaymentGateway from '../../pages/Setting/Payment/SettingsPaymentGateway.js'; +import { API, showError } from '../../helpers'; +import { useTranslation } from 'react-i18next'; + +const PaymentSetting = () => { + const { t } = useTranslation(); + let [inputs, setInputs] = useState({ + ServerAddress: '', + PayAddress: '', + EpayId: '', + EpayKey: '', + Price: 7.3, + MinTopUp: 1, + TopupGroupRatio: '', + CustomCallbackAddress: '', + PayMethods: '', + }); + + let [loading, setLoading] = useState(false); + + const getOptions = async () => { + const res = await API.get('/api/option/'); + const { success, message, data } = res.data; + if (success) { + let newInputs = {}; + data.forEach((item) => { + switch (item.key) { + case 'TopupGroupRatio': + try { + newInputs[item.key] = JSON.stringify(JSON.parse(item.value), null, 2); + } catch (error) { + console.error('解析TopupGroupRatio出错:', error); + newInputs[item.key] = item.value; + } + break; + case 'Price': + case 'MinTopUp': + newInputs[item.key] = parseFloat(item.value); + break; + default: + if (item.key.endsWith('Enabled')) { + newInputs[item.key] = item.value === 'true' ? true : false; + } else { + newInputs[item.key] = item.value; + } + break; + } + }); + + setInputs(newInputs); + } else { + showError(t(message)); + } + }; + + async function onRefresh() { + try { + setLoading(true); + await getOptions(); + } catch (error) { + showError(t('刷新失败')); + } finally { + setLoading(false); + } + } + + useEffect(() => { + onRefresh(); + }, []); + + return ( + <> + + + + + + + + + + ); +}; + +export default PaymentSetting; \ No newline at end of file diff --git a/web/src/components/settings/SystemSetting.js b/web/src/components/settings/SystemSetting.js index 1236ef2e..b5829f31 100644 --- a/web/src/components/settings/SystemSetting.js +++ b/web/src/components/settings/SystemSetting.js @@ -17,7 +17,6 @@ import { removeTrailingSlash, showError, showSuccess, - verifyJSON, } from '../../helpers'; import axios from 'axios'; @@ -42,17 +41,9 @@ const SystemSetting = () => { SMTPAccount: '', SMTPFrom: '', SMTPToken: '', - ServerAddress: '', WorkerUrl: '', WorkerValidKey: '', WorkerAllowHttpImageRequestEnabled: '', - EpayId: '', - EpayKey: '', - Price: 7.3, - MinTopUp: 1, - TopupGroupRatio: '', - PayAddress: '', - CustomCallbackAddress: '', Footer: '', WeChatAuthEnabled: '', WeChatServerAddress: '', @@ -73,7 +64,6 @@ const SystemSetting = () => { LinuxDOOAuthEnabled: '', LinuxDOClientId: '', LinuxDOClientSecret: '', - PayMethods: '', }); const [originInputs, setOriginInputs] = useState({}); @@ -200,11 +190,6 @@ const SystemSetting = () => { setInputs(values); }; - const submitServerAddress = async () => { - let ServerAddress = removeTrailingSlash(inputs.ServerAddress); - await updateOptions([{ key: 'ServerAddress', value: ServerAddress }]); - }; - const submitWorker = async () => { let WorkerUrl = removeTrailingSlash(inputs.WorkerUrl); const options = [ @@ -220,56 +205,6 @@ const SystemSetting = () => { await updateOptions(options); }; - const submitPayAddress = async () => { - if (inputs.ServerAddress === '') { - showError('请先填写服务器地址'); - return; - } - if (originInputs['TopupGroupRatio'] !== inputs.TopupGroupRatio) { - if (!verifyJSON(inputs.TopupGroupRatio)) { - showError('充值分组倍率不是合法的 JSON 字符串'); - return; - } - } - if (originInputs['PayMethods'] !== inputs.PayMethods) { - if (!verifyJSON(inputs.PayMethods)) { - showError('充值方式设置不是合法的 JSON 字符串'); - return; - } - } - - const options = [ - { key: 'PayAddress', value: removeTrailingSlash(inputs.PayAddress) }, - ]; - - if (inputs.EpayId !== '') { - options.push({ key: 'EpayId', value: inputs.EpayId }); - } - if (inputs.EpayKey !== undefined && inputs.EpayKey !== '') { - options.push({ key: 'EpayKey', value: inputs.EpayKey }); - } - if (inputs.Price !== '') { - options.push({ key: 'Price', value: inputs.Price.toString() }); - } - if (inputs.MinTopUp !== '') { - options.push({ key: 'MinTopUp', value: inputs.MinTopUp.toString() }); - } - if (inputs.CustomCallbackAddress !== '') { - options.push({ - key: 'CustomCallbackAddress', - value: inputs.CustomCallbackAddress, - }); - } - if (originInputs['TopupGroupRatio'] !== inputs.TopupGroupRatio) { - options.push({ key: 'TopupGroupRatio', value: inputs.TopupGroupRatio }); - } - if (originInputs['PayMethods'] !== inputs.PayMethods) { - options.push({ key: 'PayMethods', value: inputs.PayMethods }); - } - - await updateOptions(options); - }; - const submitSMTP = async () => { const options = []; @@ -551,17 +486,6 @@ const SystemSetting = () => { marginTop: '10px', }} > - - - - - - @@ -604,80 +528,6 @@ const SystemSetting = () => { - - - - (当前仅支持易支付接口,默认使用上方服务器地址作为回调地址!) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { + if (props.options && formApiRef.current) { + const currentInputs = { ServerAddress: props.options.ServerAddress || '' }; + setInputs(currentInputs); + formApiRef.current.setValues(currentInputs); + } + }, [props.options]); + + const handleFormChange = (values) => { + setInputs(values); + }; + + const submitServerAddress = async () => { + setLoading(true); + try { + let ServerAddress = removeTrailingSlash(inputs.ServerAddress); + const res = await API.put('/api/option/', { + key: 'ServerAddress', + value: ServerAddress, + }); + if (res.data.success) { + showSuccess(t('更新成功')); + props.refresh && props.refresh(); + } else { + showError(res.data.message); + } + } catch (error) { + showError(t('更新失败')); + } + setLoading(false); + }; + + return ( + +
(formApiRef.current = api)} + > + + + + +
+
+ ); +} \ No newline at end of file diff --git a/web/src/pages/Setting/Payment/SettingsPaymentGateway.js b/web/src/pages/Setting/Payment/SettingsPaymentGateway.js new file mode 100644 index 00000000..0bb63b53 --- /dev/null +++ b/web/src/pages/Setting/Payment/SettingsPaymentGateway.js @@ -0,0 +1,218 @@ +import React, { useEffect, useState, useRef } from 'react'; +import { + Button, + Form, + Row, + Col, + Typography, + Spin, +} from '@douyinfe/semi-ui'; +const { Text } = Typography; +import { + API, + removeTrailingSlash, + showError, + showSuccess, + verifyJSON, +} from '../../../helpers'; +import { useTranslation } from 'react-i18next'; + +export default function SettingsPaymentGateway(props) { + const { t } = useTranslation(); + const [loading, setLoading] = useState(false); + const [inputs, setInputs] = useState({ + PayAddress: '', + EpayId: '', + EpayKey: '', + Price: 7.3, + MinTopUp: 1, + TopupGroupRatio: '', + CustomCallbackAddress: '', + PayMethods: '', + }); + const [originInputs, setOriginInputs] = useState({}); + const formApiRef = useRef(null); + + useEffect(() => { + if (props.options && formApiRef.current) { + const currentInputs = { + PayAddress: props.options.PayAddress || '', + EpayId: props.options.EpayId || '', + EpayKey: props.options.EpayKey || '', + Price: props.options.Price !== undefined ? parseFloat(props.options.Price) : 7.3, + MinTopUp: props.options.MinTopUp !== undefined ? parseFloat(props.options.MinTopUp) : 1, + TopupGroupRatio: props.options.TopupGroupRatio || '', + CustomCallbackAddress: props.options.CustomCallbackAddress || '', + PayMethods: props.options.PayMethods || '', + }; + setInputs(currentInputs); + setOriginInputs({ ...currentInputs }); + formApiRef.current.setValues(currentInputs); + } + }, [props.options]); + + const handleFormChange = (values) => { + setInputs(values); + }; + + const submitPayAddress = async () => { + if (props.options.ServerAddress === '') { + showError(t('请先填写服务器地址')); + return; + } + + if (originInputs['TopupGroupRatio'] !== inputs.TopupGroupRatio) { + if (!verifyJSON(inputs.TopupGroupRatio)) { + showError(t('充值分组倍率不是合法的 JSON 字符串')); + return; + } + } + + if (originInputs['PayMethods'] !== inputs.PayMethods) { + if (!verifyJSON(inputs.PayMethods)) { + showError(t('充值方式设置不是合法的 JSON 字符串')); + return; + } + } + + setLoading(true); + try { + const options = [ + { key: 'PayAddress', value: removeTrailingSlash(inputs.PayAddress) }, + ]; + + if (inputs.EpayId !== '') { + options.push({ key: 'EpayId', value: inputs.EpayId }); + } + if (inputs.EpayKey !== undefined && inputs.EpayKey !== '') { + options.push({ key: 'EpayKey', value: inputs.EpayKey }); + } + if (inputs.Price !== '') { + options.push({ key: 'Price', value: inputs.Price.toString() }); + } + if (inputs.MinTopUp !== '') { + options.push({ key: 'MinTopUp', value: inputs.MinTopUp.toString() }); + } + if (inputs.CustomCallbackAddress !== '') { + options.push({ + key: 'CustomCallbackAddress', + value: inputs.CustomCallbackAddress, + }); + } + if (originInputs['TopupGroupRatio'] !== inputs.TopupGroupRatio) { + options.push({ key: 'TopupGroupRatio', value: inputs.TopupGroupRatio }); + } + if (originInputs['PayMethods'] !== inputs.PayMethods) { + options.push({ key: 'PayMethods', value: inputs.PayMethods }); + } + + // 发送请求 + const requestQueue = options.map(opt => + API.put('/api/option/', { + key: opt.key, + value: opt.value, + }) + ); + + const results = await Promise.all(requestQueue); + + // 检查所有请求是否成功 + const errorResults = results.filter(res => !res.data.success); + if (errorResults.length > 0) { + errorResults.forEach(res => { + showError(res.data.message); + }); + } else { + showSuccess(t('更新成功')); + // 更新本地存储的原始值 + setOriginInputs({ ...inputs }); + props.refresh && props.refresh(); + } + } catch (error) { + showError(t('更新失败')); + } + setLoading(false); + }; + + return ( + +
(formApiRef.current = api)} + > + + + {t('(当前仅支持易支付接口,默认使用上方服务器地址作为回调地址!)')} + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ ); +} \ No newline at end of file diff --git a/web/src/pages/Setting/index.js b/web/src/pages/Setting/index.js index 09b9acdf..d0ae763b 100644 --- a/web/src/pages/Setting/index.js +++ b/web/src/pages/Setting/index.js @@ -11,7 +11,8 @@ import { MoreHorizontal, LayoutDashboard, MessageSquare, - Palette + Palette, + CreditCard } from 'lucide-react'; import SystemSetting from '../../components/settings/SystemSetting.js'; @@ -24,6 +25,7 @@ import DashboardSetting from '../../components/settings/DashboardSetting.js'; import RatioSetting from '../../components/settings/RatioSetting.js'; import ChatsSetting from '../../components/settings/ChatsSetting.js'; import DrawingSetting from '../../components/settings/DrawingSetting.js'; +import PaymentSetting from '../../components/settings/PaymentSetting.js'; const Setting = () => { const { t } = useTranslation(); @@ -63,6 +65,16 @@ const Setting = () => { content: , itemKey: 'drawing', }); + panes.push({ + tab: ( + + + {t('支付设置')} + + ), + content: , + itemKey: 'payment', + }); panes.push({ tab: (