diff --git a/web/air/src/components/OperationSetting.js b/web/air/src/components/OperationSetting.js
index 874c5524..b823bb28 100644
--- a/web/air/src/components/OperationSetting.js
+++ b/web/air/src/components/OperationSetting.js
@@ -11,11 +11,10 @@ const OperationSetting = () => {
QuotaRemindThreshold: 0,
PreConsumedQuota: 0,
ModelRatio: '',
- ModelPrice: '',
+ CompletionRatio: '',
GroupRatio: '',
TopUpLink: '',
ChatLink: '',
- ChatLink2: '', // 添加的新状态变量
QuotaPerUnit: 0,
AutomaticDisableChannelEnabled: '',
AutomaticEnableChannelEnabled: '',
@@ -23,32 +22,25 @@ const OperationSetting = () => {
LogConsumeEnabled: '',
DisplayInCurrencyEnabled: '',
DisplayTokenStatEnabled: '',
- MjNotifyEnabled: '',
- DrawingEnabled: '',
- DataExportEnabled: '',
- DataExportDefaultTime: 'hour',
- DataExportInterval: 5,
- DefaultCollapseSidebar: '', // 默认折叠侧边栏
+ ApproximateTokenEnabled: '',
RetryTimes: 0
});
const [originInputs, setOriginInputs] = useState({});
let [loading, setLoading] = useState(false);
let [historyTimestamp, setHistoryTimestamp] = useState(timestamp2string(now.getTime() / 1000 - 30 * 24 * 3600)); // a month ago
- // 精确时间选项(小时,天,周)
- const timeOptions = [
- { key: 'hour', text: '小时', value: 'hour' },
- { key: 'day', text: '天', value: 'day' },
- { key: 'week', text: '周', value: 'week' }
- ];
+
const getOptions = async () => {
const res = await API.get('/api/option/');
const { success, message, data } = res.data;
if (success) {
let newInputs = {};
data.forEach((item) => {
- if (item.key === 'ModelRatio' || item.key === 'GroupRatio' || item.key === 'ModelPrice') {
+ if (item.key === 'ModelRatio' || item.key === 'GroupRatio' || item.key === 'CompletionRatio') {
item.value = JSON.stringify(JSON.parse(item.value), null, 2);
}
+ if (item.value === '{}') {
+ item.value = '';
+ }
newInputs[item.key] = item.value;
});
setInputs(newInputs);
@@ -67,10 +59,6 @@ const OperationSetting = () => {
if (key.endsWith('Enabled')) {
value = inputs[key] === 'true' ? 'false' : 'true';
}
- if (key === 'DefaultCollapseSidebar') {
- value = inputs[key] === 'true' ? 'false' : 'true';
- }
- console.log(key, value);
const res = await API.put('/api/option/', {
key,
value
@@ -85,12 +73,7 @@ const OperationSetting = () => {
};
const handleInputChange = async (e, { name, value }) => {
- if (name.endsWith('Enabled') || name === 'DataExportInterval' || name === 'DataExportDefaultTime' || name === 'DefaultCollapseSidebar') {
- if (name === 'DataExportDefaultTime') {
- localStorage.setItem('data_export_default_time', value);
- } else if (name === 'MjNotifyEnabled') {
- localStorage.setItem('mj_notify_enabled', value);
- }
+ if (name.endsWith('Enabled')) {
await updateOption(name, value);
} else {
setInputs((inputs) => ({ ...inputs, [name]: value }));
@@ -122,12 +105,12 @@ const OperationSetting = () => {
}
await updateOption('GroupRatio', inputs.GroupRatio);
}
- if (originInputs['ModelPrice'] !== inputs.ModelPrice) {
- if (!verifyJSON(inputs.ModelPrice)) {
- showError('模型固定价格不是合法的 JSON 字符串');
+ if (originInputs['CompletionRatio'] !== inputs.CompletionRatio) {
+ if (!verifyJSON(inputs.CompletionRatio)) {
+ showError('补全倍率不是合法的 JSON 字符串');
return;
}
- await updateOption('ModelPrice', inputs.ModelPrice);
+ await updateOption('CompletionRatio', inputs.CompletionRatio);
}
break;
case 'quota':
@@ -151,9 +134,6 @@ const OperationSetting = () => {
if (originInputs['ChatLink'] !== inputs.ChatLink) {
await updateOption('ChatLink', inputs.ChatLink);
}
- if (originInputs['ChatLink2'] !== inputs.ChatLink2) {
- await updateOption('ChatLink2', inputs.ChatLink2);
- }
if (originInputs['QuotaPerUnit'] !== inputs.QuotaPerUnit) {
await updateOption('QuotaPerUnit', inputs.QuotaPerUnit);
}
@@ -174,80 +154,72 @@ const OperationSetting = () => {
}
showError('日志清理失败:' + message);
};
+
return (
- )
- ;
+ );
};
export default OperationSetting;
diff --git a/web/air/src/components/OtherSetting.js b/web/air/src/components/OtherSetting.js
index 014492de..ae924d9f 100644
--- a/web/air/src/components/OtherSetting.js
+++ b/web/air/src/components/OtherSetting.js
@@ -1,16 +1,18 @@
-import React, { useEffect, useRef, useState } from 'react';
-import { Banner, Button, Col, Form, Row } from '@douyinfe/semi-ui';
+import React, { useEffect, useState } from 'react';
+import { Button, Divider, Form, Grid, Header, Message, Modal } from 'semantic-ui-react';
import { API, showError, showSuccess } from '../helpers';
import { marked } from 'marked';
+import { Link } from 'react-router-dom';
const OtherSetting = () => {
let [inputs, setInputs] = useState({
+ Footer: '',
Notice: '',
+ About: '',
SystemName: '',
Logo: '',
- Footer: '',
- About: '',
- HomePageContent: ''
+ HomePageContent: '',
+ Theme: ''
});
let [loading, setLoading] = useState(false);
const [showUpdateModal, setShowUpdateModal] = useState(false);
@@ -19,6 +21,25 @@ const OtherSetting = () => {
content: ''
});
+ const getOptions = async () => {
+ const res = await API.get('/api/option/');
+ const { success, message, data } = res.data;
+ if (success) {
+ let newInputs = {};
+ data.forEach((item) => {
+ if (item.key in inputs) {
+ newInputs[item.key] = item.value;
+ }
+ });
+ setInputs(newInputs);
+ } else {
+ showError(message);
+ }
+ };
+
+ useEffect(() => {
+ getOptions().then();
+ }, []);
const updateOption = async (key, value) => {
setLoading(true);
@@ -35,103 +56,37 @@ const OtherSetting = () => {
setLoading(false);
};
- const [loadingInput, setLoadingInput] = useState({
- Notice: false,
- SystemName: false,
- Logo: false,
- HomePageContent: false,
- About: false,
- Footer: false
- });
- const handleInputChange = async (value, e) => {
- const name = e.target.id;
+ const handleInputChange = async (e, { name, value }) => {
setInputs((inputs) => ({ ...inputs, [name]: value }));
};
- // 通用设置
- const formAPISettingGeneral = useRef();
- // 通用设置 - Notice
const submitNotice = async () => {
- try {
- setLoadingInput((loadingInput) => ({ ...loadingInput, Notice: true }));
- await updateOption('Notice', inputs.Notice);
- showSuccess('公告已更新');
- } catch (error) {
- console.error('公告更新失败', error);
- showError('公告更新失败');
- } finally {
- setLoadingInput((loadingInput) => ({ ...loadingInput, Notice: false }));
- }
- };
- // 个性化设置
- const formAPIPersonalization = useRef();
- // 个性化设置 - SystemName
- const submitSystemName = async () => {
- try {
- setLoadingInput((loadingInput) => ({ ...loadingInput, SystemName: true }));
- await updateOption('SystemName', inputs.SystemName);
- showSuccess('系统名称已更新');
- } catch (error) {
- console.error('系统名称更新失败', error);
- showError('系统名称更新失败');
- } finally {
- setLoadingInput((loadingInput) => ({ ...loadingInput, SystemName: false }));
- }
+ await updateOption('Notice', inputs.Notice);
};
- // 个性化设置 - Logo
- const submitLogo = async () => {
- try {
- setLoadingInput((loadingInput) => ({ ...loadingInput, Logo: true }));
- await updateOption('Logo', inputs.Logo);
- showSuccess('Logo 已更新');
- } catch (error) {
- console.error('Logo 更新失败', error);
- showError('Logo 更新失败');
- } finally {
- setLoadingInput((loadingInput) => ({ ...loadingInput, Logo: false }));
- }
- };
- // 个性化设置 - 首页内容
- const submitOption = async (key) => {
- try {
- setLoadingInput((loadingInput) => ({ ...loadingInput, HomePageContent: true }));
- await updateOption(key, inputs[key]);
- showSuccess('首页内容已更新');
- } catch (error) {
- console.error('首页内容更新失败', error);
- showError('首页内容更新失败');
- } finally {
- setLoadingInput((loadingInput) => ({ ...loadingInput, HomePageContent: false }));
- }
- };
- // 个性化设置 - 关于
- const submitAbout = async () => {
- try {
- setLoadingInput((loadingInput) => ({ ...loadingInput, About: true }));
- await updateOption('About', inputs.About);
- showSuccess('关于内容已更新');
- } catch (error) {
- console.error('关于内容更新失败', error);
- showError('关于内容更新失败');
- } finally {
- setLoadingInput((loadingInput) => ({ ...loadingInput, About: false }));
- }
- };
- // 个性化设置 - 页脚
const submitFooter = async () => {
- try {
- setLoadingInput((loadingInput) => ({ ...loadingInput, Footer: true }));
- await updateOption('Footer', inputs.Footer);
- showSuccess('页脚内容已更新');
- } catch (error) {
- console.error('页脚内容更新失败', error);
- showError('页脚内容更新失败');
- } finally {
- setLoadingInput((loadingInput) => ({ ...loadingInput, Footer: false }));
- }
+ await updateOption('Footer', inputs.Footer);
};
+ const submitSystemName = async () => {
+ await updateOption('SystemName', inputs.SystemName);
+ };
+
+ const submitTheme = async () => {
+ await updateOption('Theme', inputs.Theme);
+ };
+
+ const submitLogo = async () => {
+ await updateOption('Logo', inputs.Logo);
+ };
+
+ const submitAbout = async () => {
+ await updateOption('About', inputs.About);
+ };
+
+ const submitOption = async (key) => {
+ await updateOption(key, inputs[key]);
+ };
const openGitHubRelease = () => {
window.location =
@@ -153,125 +108,117 @@ const OtherSetting = () => {
setShowUpdateModal(true);
}
};
- const getOptions = async () => {
- const res = await API.get('/api/option/');
- const { success, message, data } = res.data;
- if (success) {
- let newInputs = {};
- data.forEach((item) => {
- if (item.key in inputs) {
- newInputs[item.key] = item.value;
- }
- });
- setInputs(newInputs);
- formAPISettingGeneral.current.setValues(newInputs);
- formAPIPersonalization.current.setValues(newInputs);
- } else {
- showError(message);
- }
- };
-
- useEffect(() => {
- getOptions();
- }, []);
-
return (
-
-
- {/* 通用设置 */}
-
+
+
+ 检查更新
+
-
-
+
+ 保存公告
+
+
+
+
+
+ 设置系统名称
+
+ 主题名称(当前可用主题)}
+ placeholder='请输入主题名称'
+ value={inputs.Theme}
+ name='Theme'
+ onChange={handleInputChange}
+ />
+
+ 设置主题(重启生效)
+
+
+
+ 设置 Logo
+
+
+
+ submitOption('HomePageContent')}>保存首页内容
+
+
+
+ 保存关于
+ 移除 One API
+ 的版权标识必须首先获得授权,项目维护需要花费大量精力,如果本项目对你有意义,请主动支持本项目。
+
+
+
+ 设置页脚
- {/* 个性化设置 */}
-
-
-
-
-
-
-
-
-
- {/* */}
-
-
-
-
-
-
- {/* setShowUpdateModal(false)}*/}
- {/* onOpen={() => setShowUpdateModal(true)}*/}
- {/* open={showUpdateModal}*/}
- {/*>*/}
- {/* 新版本:{updateData.tag_name}*/}
- {/* */}
- {/* */}
- {/* */}
- {/* */}
- {/* */}
- {/* */}
- {/* */}
- {/* */}
- {/**/}
-
+
+ setShowUpdateModal(false)}
+ onOpen={() => setShowUpdateModal(true)}
+ open={showUpdateModal}
+ >
+ 新版本:{updateData.tag_name}
+
+
+
+
+
+
+
+
+
+
);
};
diff --git a/web/air/src/components/SystemSetting.js b/web/air/src/components/SystemSetting.js
index 213685b8..09b98665 100644
--- a/web/air/src/components/SystemSetting.js
+++ b/web/air/src/components/SystemSetting.js
@@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react';
-import { Button, Divider, Form, Grid, Header, Message, Modal } from 'semantic-ui-react';
-import { API, removeTrailingSlash, showError, verifyJSON } from '../helpers';
+import { Button, Divider, Form, Grid, Header, Modal, Message } from 'semantic-ui-react';
+import { API, removeTrailingSlash, showError } from '../helpers';
const SystemSetting = () => {
let [inputs, setInputs] = useState({
@@ -17,28 +17,19 @@ const SystemSetting = () => {
SMTPFrom: '',
SMTPToken: '',
ServerAddress: '',
- EpayId: '',
- EpayKey: '',
- Price: 7.3,
- MinTopUp: 1,
- TopupGroupRatio: '',
- PayAddress: '',
- CustomCallbackAddress: '',
Footer: '',
WeChatAuthEnabled: '',
WeChatServerAddress: '',
WeChatServerToken: '',
WeChatAccountQRCodeImageURL: '',
+ MessagePusherAddress: '',
+ MessagePusherToken: '',
TurnstileCheckEnabled: '',
TurnstileSiteKey: '',
TurnstileSecretKey: '',
RegisterEnabled: '',
EmailDomainRestrictionEnabled: '',
- EmailDomainWhitelist: '',
- // telegram login
- TelegramOAuthEnabled: '',
- TelegramBotToken: '',
- TelegramBotName: ''
+ EmailDomainWhitelist: ''
});
const [originInputs, setOriginInputs] = useState({});
let [loading, setLoading] = useState(false);
@@ -52,9 +43,6 @@ const SystemSetting = () => {
if (success) {
let newInputs = {};
data.forEach((item) => {
- if (item.key === 'TopupGroupRatio') {
- item.value = JSON.stringify(JSON.parse(item.value), null, 2);
- }
newInputs[item.key] = item.value;
});
setInputs({
@@ -83,7 +71,6 @@ const SystemSetting = () => {
case 'EmailVerificationEnabled':
case 'GitHubOAuthEnabled':
case 'WeChatAuthEnabled':
- case 'TelegramOAuthEnabled':
case 'TurnstileCheckEnabled':
case 'EmailDomainRestrictionEnabled':
case 'RegisterEnabled':
@@ -101,9 +88,6 @@ const SystemSetting = () => {
if (key === 'EmailDomainWhitelist') {
value = value.split(',');
}
- if (key === 'Price') {
- value = parseFloat(value);
- }
setInputs((inputs) => ({
...inputs, [key]: value
}));
@@ -123,10 +107,6 @@ const SystemSetting = () => {
name === 'Notice' ||
name.startsWith('SMTP') ||
name === 'ServerAddress' ||
- name === 'EpayId' ||
- name === 'EpayKey' ||
- name === 'Price' ||
- name === 'PayAddress' ||
name === 'GitHubClientId' ||
name === 'GitHubClientSecret' ||
name === 'WeChatServerAddress' ||
@@ -134,10 +114,7 @@ const SystemSetting = () => {
name === 'WeChatAccountQRCodeImageURL' ||
name === 'TurnstileSiteKey' ||
name === 'TurnstileSecretKey' ||
- name === 'EmailDomainWhitelist' ||
- name === 'TopupGroupRatio' ||
- name === 'TelegramBotToken' ||
- name === 'TelegramBotName'
+ name === 'EmailDomainWhitelist'
) {
setInputs((inputs) => ({ ...inputs, [name]: value }));
} else {
@@ -150,29 +127,6 @@ const SystemSetting = () => {
await updateOption('ServerAddress', ServerAddress);
};
- const submitPayAddress = async () => {
- if (inputs.ServerAddress === '') {
- showError('请先填写服务器地址');
- return;
- }
- if (originInputs['TopupGroupRatio'] !== inputs.TopupGroupRatio) {
- if (!verifyJSON(inputs.TopupGroupRatio)) {
- showError('充值分组倍率不是合法的 JSON 字符串');
- return;
- }
- await updateOption('TopupGroupRatio', inputs.TopupGroupRatio);
- }
- let PayAddress = removeTrailingSlash(inputs.PayAddress);
- await updateOption('PayAddress', PayAddress);
- if (inputs.EpayId !== '') {
- await updateOption('EpayId', inputs.EpayId);
- }
- if (inputs.EpayKey !== '') {
- await updateOption('EpayKey', inputs.EpayKey);
- }
- await updateOption('Price', '' + inputs.Price);
- };
-
const submitSMTP = async () => {
if (originInputs['SMTPServer'] !== inputs.SMTPServer) {
await updateOption('SMTPServer', inputs.SMTPServer);
@@ -231,6 +185,21 @@ const SystemSetting = () => {
}
};
+ const submitMessagePusher = async () => {
+ if (originInputs['MessagePusherAddress'] !== inputs.MessagePusherAddress) {
+ await updateOption(
+ 'MessagePusherAddress',
+ removeTrailingSlash(inputs.MessagePusherAddress)
+ );
+ }
+ if (
+ originInputs['MessagePusherToken'] !== inputs.MessagePusherToken &&
+ inputs.MessagePusherToken !== ''
+ ) {
+ await updateOption('MessagePusherToken', inputs.MessagePusherToken);
+ }
+ };
+
const submitGitHubOAuth = async () => {
if (originInputs['GitHubClientId'] !== inputs.GitHubClientId) {
await updateOption('GitHubClientId', inputs.GitHubClientId);
@@ -243,12 +212,6 @@ const SystemSetting = () => {
}
};
- const submitTelegramSettings = async () => {
- // await updateOption('TelegramOAuthEnabled', inputs.TelegramOAuthEnabled);
- await updateOption('TelegramBotToken', inputs.TelegramBotToken);
- await updateOption('TelegramBotName', inputs.TelegramBotName);
- };
-
const submitTurnstile = async () => {
if (originInputs['TurnstileSiteKey'] !== inputs.TurnstileSiteKey) {
await updateOption('TurnstileSiteKey', inputs.TurnstileSiteKey);
@@ -267,27 +230,27 @@ const SystemSetting = () => {
setRestrictedDomainInput('');
setInputs({
...inputs,
- EmailDomainWhitelist: [...localDomainList, restrictedDomainInput]
+ EmailDomainWhitelist: [...localDomainList, restrictedDomainInput],
});
setEmailDomainWhitelist([...EmailDomainWhitelist, {
key: restrictedDomainInput,
text: restrictedDomainInput,
- value: restrictedDomainInput
+ value: restrictedDomainInput,
}]);
}
- };
+ }
return (
+
+
@@ -295,77 +258,12 @@ const SystemSetting = () => {
更新服务器地址
- 支付设置(当前仅支持易支付接口,默认使用上方服务器地址作为回调地址!)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 更新支付设置
-
-
-
+
{
@@ -383,7 +281,7 @@ const SystemSetting = () => {
-
+
配置邮箱域名白名单
用以防止恶意用户利用临时邮箱批量注册
{
+
}
@@ -478,8 +370,8 @@ const SystemSetting = () => {
submitNewRestrictedDomain();
}
}}
- autoComplete="new-password"
- placeholder="输入新的允许的邮箱域名"
+ autoComplete='new-password'
+ placeholder='输入新的允许的邮箱域名'
value={restrictedDomainInput}
onChange={(e, { value }) => {
setRestrictedDomainInput(value);
@@ -488,62 +380,62 @@ const SystemSetting = () => {
保存邮箱域名白名单设置
-
+
保存 SMTP 设置
-
+
配置 GitHub OAuth App
用以支持通过 GitHub 进行登录注册,
-
+
点击此处
管理你的 GitHub OAuth App
@@ -556,34 +448,34 @@ const SystemSetting = () => {
保存 GitHub OAuth 设置
-
+
配置 WeChat Server
用以支持通过微信进行登录注册,
点击此处
@@ -592,61 +484,76 @@ const SystemSetting = () => {
保存 WeChat Server 设置
-
-
+
+ 配置 Message Pusher
+
+ 用以推送报警信息,
+
+ 点击此处
+
+ 了解 Message Pusher
+
+
+
-
- 保存 Telegram 登录设置
+
+ 保存 Message Pusher 设置
-
+
配置 Turnstile
用以支持用户校验,
-
+
点击此处
管理你的 Turnstile Sites,推荐选择 Invisible Widget Type
@@ -654,21 +561,21 @@ const SystemSetting = () => {