/* Copyright (C) 2025 QuantumNous This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . For commercial licensing, please contact support@quantumnous.com */ import React, { useEffect, useState, useRef, useMemo } from 'react'; import { Banner, Button, Col, Form, Row, Spin, Modal, Select, InputGroup, Input, } from '@douyinfe/semi-ui'; import { compareObjects, API, showError, showSuccess, showWarning, } from '../../../helpers'; import { useTranslation } from 'react-i18next'; export default function GeneralSettings(props) { const { t } = useTranslation(); const [loading, setLoading] = useState(false); const [showQuotaWarning, setShowQuotaWarning] = useState(false); const [inputs, setInputs] = useState({ TopUpLink: '', 'general_setting.docs_link': '', 'general_setting.quota_display_type': 'USD', 'general_setting.custom_currency_symbol': '¤', 'general_setting.custom_currency_exchange_rate': '', QuotaPerUnit: '', RetryTimes: '', USDExchangeRate: '', DisplayTokenStatEnabled: false, DefaultCollapseSidebar: false, DemoSiteEnabled: false, SelfUseModeEnabled: false, }); const refForm = useRef(); const [inputsRow, setInputsRow] = useState(inputs); function handleFieldChange(fieldName) { return (value) => { setInputs((inputs) => ({ ...inputs, [fieldName]: value })); }; } function onSubmit() { const updateArray = compareObjects(inputs, inputsRow); if (!updateArray.length) return showWarning(t('你似乎并没有修改什么')); const requestQueue = updateArray.map((item) => { let value = ''; if (typeof inputs[item.key] === 'boolean') { value = String(inputs[item.key]); } else { value = inputs[item.key]; } return API.put('/api/option/', { key: item.key, value, }); }); setLoading(true); Promise.all(requestQueue) .then((res) => { if (requestQueue.length === 1) { if (res.includes(undefined)) return; } else if (requestQueue.length > 1) { if (res.includes(undefined)) return showError(t('部分保存失败,请重试')); } showSuccess(t('保存成功')); props.refresh(); }) .catch(() => { showError(t('保存失败,请重试')); }) .finally(() => { setLoading(false); }); } // 计算展示在输入框中的“1 USD = X ”中的 X const combinedRate = useMemo(() => { const type = inputs['general_setting.quota_display_type']; if (type === 'USD') return '1'; if (type === 'CNY') return String(inputs['USDExchangeRate'] || ''); if (type === 'TOKENS') return String(inputs['QuotaPerUnit'] || ''); if (type === 'CUSTOM') return String( inputs['general_setting.custom_currency_exchange_rate'] || '', ); return ''; }, [inputs]); const onCombinedRateChange = (val) => { const type = inputs['general_setting.quota_display_type']; if (type === 'CNY') { handleFieldChange('USDExchangeRate')(val); } else if (type === 'TOKENS') { handleFieldChange('QuotaPerUnit')(val); } else if (type === 'CUSTOM') { handleFieldChange('general_setting.custom_currency_exchange_rate')(val); } }; useEffect(() => { const currentInputs = {}; for (let key in props.options) { if (Object.keys(inputs).includes(key)) { currentInputs[key] = props.options[key]; } } // 若旧字段存在且新字段缺失,则做一次兜底映射 if ( currentInputs['general_setting.quota_display_type'] === undefined && props.options?.DisplayInCurrencyEnabled !== undefined ) { currentInputs['general_setting.quota_display_type'] = props.options .DisplayInCurrencyEnabled ? 'USD' : 'TOKENS'; } // 回填自定义货币相关字段(如果后端已存在) if (props.options['general_setting.custom_currency_symbol'] !== undefined) { currentInputs['general_setting.custom_currency_symbol'] = props.options['general_setting.custom_currency_symbol']; } if ( props.options['general_setting.custom_currency_exchange_rate'] !== undefined ) { currentInputs['general_setting.custom_currency_exchange_rate'] = props.options['general_setting.custom_currency_exchange_rate']; } setInputs(currentInputs); setInputsRow(structuredClone(currentInputs)); refForm.current.setValues(currentInputs); }, [props.options]); return ( <>
(refForm.current = formAPI)} style={{ marginBottom: 15 }} > {/* 单位美元额度已合入汇率组合控件(TOKENS 模式下编辑),不再单独展示 */}
setShowQuotaWarning(false)} onCancel={() => setShowQuotaWarning(false)} closeOnEsc={true} width={500} > ); }