Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 

218 строки
6.3 KiB

  1. /*
  2. Copyright (C) 2025 QuantumNous
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <https://www.gnu.org/licenses/>.
  13. For commercial licensing, please contact support@quantumnous.com
  14. */
  15. import React, { useEffect, useState } from 'react';
  16. import { Layout, TabPane, Tabs } from '@douyinfe/semi-ui';
  17. import { useNavigate, useLocation } from 'react-router-dom';
  18. import { useTranslation } from 'react-i18next';
  19. import {
  20. Settings,
  21. Calculator,
  22. Gauge,
  23. Shapes,
  24. Cog,
  25. MoreHorizontal,
  26. LayoutDashboard,
  27. MessageSquare,
  28. Palette,
  29. CreditCard,
  30. Server,
  31. Activity,
  32. } from 'lucide-react';
  33. import SystemSetting from '../../components/settings/SystemSetting';
  34. import { isRoot } from '../../helpers';
  35. import OtherSetting from '../../components/settings/OtherSetting';
  36. import OperationSetting from '../../components/settings/OperationSetting';
  37. import RateLimitSetting from '../../components/settings/RateLimitSetting';
  38. import ModelSetting from '../../components/settings/ModelSetting';
  39. import DashboardSetting from '../../components/settings/DashboardSetting';
  40. import RatioSetting from '../../components/settings/RatioSetting';
  41. import ChatsSetting from '../../components/settings/ChatsSetting';
  42. import DrawingSetting from '../../components/settings/DrawingSetting';
  43. import PaymentSetting from '../../components/settings/PaymentSetting';
  44. import ModelDeploymentSetting from '../../components/settings/ModelDeploymentSetting';
  45. import PerformanceSetting from '../../components/settings/PerformanceSetting';
  46. const Setting = () => {
  47. const { t } = useTranslation();
  48. const navigate = useNavigate();
  49. const location = useLocation();
  50. const [tabActiveKey, setTabActiveKey] = useState('1');
  51. let panes = [];
  52. if (isRoot()) {
  53. panes.push({
  54. tab: (
  55. <span style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
  56. <Settings size={18} />
  57. {t('运营设置')}
  58. </span>
  59. ),
  60. content: <OperationSetting />,
  61. itemKey: 'operation',
  62. });
  63. panes.push({
  64. tab: (
  65. <span style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
  66. <LayoutDashboard size={18} />
  67. {t('仪表盘设置')}
  68. </span>
  69. ),
  70. content: <DashboardSetting />,
  71. itemKey: 'dashboard',
  72. });
  73. panes.push({
  74. tab: (
  75. <span style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
  76. <MessageSquare size={18} />
  77. {t('聊天设置')}
  78. </span>
  79. ),
  80. content: <ChatsSetting />,
  81. itemKey: 'chats',
  82. });
  83. panes.push({
  84. tab: (
  85. <span style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
  86. <Palette size={18} />
  87. {t('绘图设置')}
  88. </span>
  89. ),
  90. content: <DrawingSetting />,
  91. itemKey: 'drawing',
  92. });
  93. panes.push({
  94. tab: (
  95. <span style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
  96. <CreditCard size={18} />
  97. {t('支付设置')}
  98. </span>
  99. ),
  100. content: <PaymentSetting />,
  101. itemKey: 'payment',
  102. });
  103. panes.push({
  104. tab: (
  105. <span style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
  106. <Calculator size={18} />
  107. {t('分组与模型定价设置')}
  108. </span>
  109. ),
  110. content: <RatioSetting />,
  111. itemKey: 'ratio',
  112. });
  113. panes.push({
  114. tab: (
  115. <span style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
  116. <Gauge size={18} />
  117. {t('速率限制设置')}
  118. </span>
  119. ),
  120. content: <RateLimitSetting />,
  121. itemKey: 'ratelimit',
  122. });
  123. panes.push({
  124. tab: (
  125. <span style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
  126. <Shapes size={18} />
  127. {t('模型相关设置')}
  128. </span>
  129. ),
  130. content: <ModelSetting />,
  131. itemKey: 'models',
  132. });
  133. panes.push({
  134. tab: (
  135. <span style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
  136. <Server size={18} />
  137. {t('模型部署设置')}
  138. </span>
  139. ),
  140. content: <ModelDeploymentSetting />,
  141. itemKey: 'model-deployment',
  142. });
  143. panes.push({
  144. tab: (
  145. <span style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
  146. <Activity size={18} />
  147. {t('性能设置')}
  148. </span>
  149. ),
  150. content: <PerformanceSetting />,
  151. itemKey: 'performance',
  152. });
  153. panes.push({
  154. tab: (
  155. <span style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
  156. <Cog size={18} />
  157. {t('系统设置')}
  158. </span>
  159. ),
  160. content: <SystemSetting />,
  161. itemKey: 'system',
  162. });
  163. panes.push({
  164. tab: (
  165. <span style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
  166. <MoreHorizontal size={18} />
  167. {t('其他设置')}
  168. </span>
  169. ),
  170. content: <OtherSetting />,
  171. itemKey: 'other',
  172. });
  173. }
  174. const onChangeTab = (key) => {
  175. setTabActiveKey(key);
  176. navigate(`?tab=${key}`);
  177. };
  178. useEffect(() => {
  179. const searchParams = new URLSearchParams(window.location.search);
  180. const tab = searchParams.get('tab');
  181. if (tab) {
  182. setTabActiveKey(tab);
  183. } else {
  184. onChangeTab('operation');
  185. }
  186. }, [location.search]);
  187. return (
  188. <div className='mt-[60px] px-2'>
  189. <Layout>
  190. <Layout.Content>
  191. <Tabs
  192. type='card'
  193. collapsible
  194. activeKey={tabActiveKey}
  195. onChange={(key) => onChangeTab(key)}
  196. >
  197. {panes.map((pane) => (
  198. <TabPane itemKey={pane.itemKey} tab={pane.tab} key={pane.itemKey}>
  199. {tabActiveKey === pane.itemKey && pane.content}
  200. </TabPane>
  201. ))}
  202. </Tabs>
  203. </Layout.Content>
  204. </Layout>
  205. </div>
  206. );
  207. };
  208. export default Setting;