Explorar el Código

refactor: Reorganize sidebar navigation and add personal settings route

1808837298@qq.com hace 1 año
padre
commit
fd22948ead

+ 11 - 0
web/src/App.js

@@ -30,6 +30,7 @@ import { useTranslation } from 'react-i18next';
 import { StatusContext } from './context/Status';
 import { setStatusData } from './helpers/data.js';
 import { API, showError } from './helpers';
+import PersonalSetting from './components/PersonalSetting.js';
 
 const Home = lazy(() => import('./pages/Home'));
 const Detail = lazy(() => import('./pages/Detail'));
@@ -177,6 +178,16 @@ function App() {
             </PrivateRoute>
           }
         />
+        <Route
+          path='/personal'
+          element={
+            <PrivateRoute>
+              <Suspense fallback={<Loading></Loading>}>
+                <PersonalSetting />
+              </Suspense>
+            </PrivateRoute>
+          }
+        />
         <Route
           path='/topup'
           element={

+ 1 - 1
web/src/components/PersonalSetting.js

@@ -393,7 +393,7 @@ const PersonalSetting = () => {
                             </div>
                         </div>
                     </Modal>
-                    <div style={{marginTop: 20}}>
+                    <div>
                         <Card
                             title={
                                 <Card.Meta

+ 232 - 109
web/src/components/SiderBar.js

@@ -28,7 +28,7 @@ import {
   IconSetting,
   IconUser
 } from '@douyinfe/semi-icons';
-import { Avatar, Dropdown, Layout, Nav, Switch } from '@douyinfe/semi-ui';
+import { Avatar, Dropdown, Layout, Nav, Switch, Divider } from '@douyinfe/semi-ui';
 import { setStatusData } from '../helpers/data.js';
 import { stringToColor } from '../helpers/render.js';
 import { useSetTheme, useTheme } from '../context/Theme/index.js';
@@ -65,35 +65,11 @@ const SiderBar = () => {
     pricing: '/pricing',
     task: '/task',
     playground: '/playground',
+    personal: '/personal',
   };
 
-  const headerButtons = useMemo(
+  const workspaceItems = useMemo(
     () => [
-      {
-        text: 'Playground',
-        itemKey: 'playground',
-        to: '/playground',
-        icon: <IconCommentStroked />,
-      },
-      {
-        text: t('渠道'),
-        itemKey: 'channel',
-        to: '/channel',
-        icon: <IconLayers />,
-        className: isAdmin() ? '' : 'tableHiddle',
-      },
-      {
-        text: t('聊天'),
-        itemKey: 'chat',
-        items: chatItems,
-        icon: <IconComment />,
-      },
-      {
-        text: t('令牌'),
-        itemKey: 'token',
-        to: '/token',
-        icon: <IconKey />,
-      },
       {
         text: t('数据看板'),
         itemKey: 'detail',
@@ -105,33 +81,19 @@ const SiderBar = () => {
             : 'tableHiddle',
       },
       {
-        text: t('兑换码'),
-        itemKey: 'redemption',
-        to: '/redemption',
-        icon: <IconGift />,
-        className: isAdmin() ? '' : 'tableHiddle',
-      },
-      {
-        text: t('钱包'),
-        itemKey: 'topup',
-        to: '/topup',
-        icon: <IconCreditCard />,
-      },
-      {
-        text: t('用户管理'),
-        itemKey: 'user',
-        to: '/user',
-        icon: <IconUser />,
-        className: isAdmin() ? '' : 'tableHiddle',
+        text: t('API令牌'),
+        itemKey: 'token',
+        to: '/token',
+        icon: <IconKey />,
       },
       {
-        text: t('日志'),
+        text: t('使用日志'),
         itemKey: 'log',
         to: '/log',
         icon: <IconHistogram />,
       },
       {
-        text: t('绘图'),
+        text: t('绘图日志'),
         itemKey: 'midjourney',
         to: '/midjourney',
         icon: <IconImage />,
@@ -141,31 +103,90 @@ const SiderBar = () => {
             : 'tableHiddle',
       },
       {
-        text: t('异步任务'),
+        text: t('任务日志'),
         itemKey: 'task',
         to: '/task',
         icon: <IconChecklistStroked />,
         className:
-            localStorage.getItem('enable_task') === 'true'
-                ? ''
-                : 'tableHiddle',
+          localStorage.getItem('enable_task') === 'true'
+            ? ''
+            : 'tableHiddle',
+      }
+    ],
+    [
+      localStorage.getItem('enable_data_export'),
+      localStorage.getItem('enable_drawing'),
+      localStorage.getItem('enable_task'),
+      t,
+    ],
+  );
+
+  const financeItems = useMemo(
+    () => [
+      {
+        text: t('钱包'),
+        itemKey: 'topup',
+        to: '/topup',
+        icon: <IconCreditCard />,
       },
       {
-        text: t('设置'),
+        text: t('个人设置'),
+        itemKey: 'personal',
+        to: '/personal',
+        icon: <IconUser />,
+      },
+    ],
+    [t],
+  );
+
+  const adminItems = useMemo(
+    () => [
+      {
+        text: t('渠道'),
+        itemKey: 'channel',
+        to: '/channel',
+        icon: <IconLayers />,
+        className: isAdmin() ? '' : 'tableHiddle',
+      },
+      {
+        text: t('兑换码'),
+        itemKey: 'redemption',
+        to: '/redemption',
+        icon: <IconGift />,
+        className: isAdmin() ? '' : 'tableHiddle',
+      },
+      {
+        text: t('用户管理'),
+        itemKey: 'user',
+        to: '/user',
+        icon: <IconUser />,
+      },
+      {
+        text: t('系统设置'),
         itemKey: 'setting',
         to: '/setting',
         icon: <IconSetting />,
       },
     ],
-    [
-      localStorage.getItem('enable_data_export'),
-      localStorage.getItem('enable_drawing'),
-      localStorage.getItem('enable_task'),
-      localStorage.getItem('chat_link'),
-      chatItems,
-      isAdmin(),
-      t,
+    [isAdmin(), t],
+  );
+
+  const chatMenuItems = useMemo(
+    () => [
+      {
+        text: 'Playground',
+        itemKey: 'playground',
+        to: '/playground',
+        icon: <IconCommentStroked />,
+      },
+      {
+        text: t('聊天'),
+        itemKey: 'chat',
+        items: chatItems,
+        icon: <IconComment />,
+      },
     ],
+    [chatItems, t],
   );
 
   useEffect(() => {
@@ -174,42 +195,56 @@ const SiderBar = () => {
       localKey = 'home';
     }
     setSelectedKeys([localKey]);
-    
+
     let chatLink = localStorage.getItem('chat_link');
     if (!chatLink) {
-        let chats = localStorage.getItem('chats');
-        if (chats) {
-            // console.log(chats);
-            try {
-                chats = JSON.parse(chats);
-                if (Array.isArray(chats)) {
-                    let chatItems = [];
-                    for (let i = 0; i < chats.length; i++) {
-                        let chat = {};
-                        for (let key in chats[i]) {
-                            chat.text = key;
-                            chat.itemKey = 'chat' + i;
-                            chat.to = '/chat/' + i;
-                        }
-                        // setRouterMap({ ...routerMap, chat: '/chat/' + i })
-                        chatItems.push(chat);
-                    }
-                    setChatItems(chatItems);
-                }
-            } catch (e) {
-                console.error(e);
-                showError('聊天数据解析失败')
+      let chats = localStorage.getItem('chats');
+      if (chats) {
+        // console.log(chats);
+        try {
+          chats = JSON.parse(chats);
+          if (Array.isArray(chats)) {
+            let chatItems = [];
+            for (let i = 0; i < chats.length; i++) {
+              let chat = {};
+              for (let key in chats[i]) {
+                chat.text = key;
+                chat.itemKey = 'chat' + i;
+                chat.to = '/chat/' + i;
+              }
+              // setRouterMap({ ...routerMap, chat: '/chat/' + i })
+              chatItems.push(chat);
             }
+            setChatItems(chatItems);
+          }
+        } catch (e) {
+          console.error(e);
+          showError('聊天数据解析失败')
         }
+      }
     }
-    
+
     setIsCollapsed(localStorage.getItem('default_collapse_sidebar') === 'true');
   }, []);
 
+  // Custom divider style
+  const dividerStyle = {
+    margin: '8px 0',
+    opacity: 0.6,
+  };
+
+  // Custom group label style
+  const groupLabelStyle = {
+    padding: '8px 16px',
+    color: 'var(--semi-color-text-2)',
+    fontSize: '12px',
+    fontWeight: 'normal',
+  };
+
   return (
     <>
       <Nav
-        style={{ maxWidth: 220, height: '100%' }}
+        style={{ maxWidth: 200, height: '100%' }}
         defaultIsCollapsed={
           localStorage.getItem('default_collapse_sidebar') === 'true'
         }
@@ -219,27 +254,27 @@ const SiderBar = () => {
         }}
         selectedKeys={selectedKeys}
         renderWrapper={({ itemElement, isSubNav, isInSubNav, props }) => {
-            let chatLink = localStorage.getItem('chat_link');
-            if (!chatLink) {
-                let chats = localStorage.getItem('chats');
-                if (chats) {
-                    chats = JSON.parse(chats);
-                    if (Array.isArray(chats) && chats.length > 0) {
-                        for (let i = 0; i < chats.length; i++) {
-                            routerMap['chat' + i] = '/chat/' + i;
-                        }
-                        if (chats.length > 1) {
-                            // delete /chat
-                            if (routerMap['chat']) {
-                                delete routerMap['chat'];
-                            }
-                        } else {
-                            // rename /chat to /chat/0
-                            routerMap['chat'] = '/chat/0';
-                        }
-                    }
+          let chatLink = localStorage.getItem('chat_link');
+          if (!chatLink) {
+            let chats = localStorage.getItem('chats');
+            if (chats) {
+              chats = JSON.parse(chats);
+              if (Array.isArray(chats) && chats.length > 0) {
+                for (let i = 0; i < chats.length; i++) {
+                  routerMap['chat' + i] = '/chat/' + i;
                 }
+                if (chats.length > 1) {
+                  // delete /chat
+                  if (routerMap['chat']) {
+                    delete routerMap['chat'];
+                  }
+                } else {
+                  // rename /chat to /chat/0
+                  routerMap['chat'] = '/chat/0';
+                }
+              }
             }
+          }
           return (
             <Link
               style={{ textDecoration: 'none' }}
@@ -249,7 +284,6 @@ const SiderBar = () => {
             </Link>
           );
         }}
-        items={headerButtons}
         onSelect={(key) => {
           if (key.itemKey.toString().startsWith('chat')) {
             styleDispatch({ type: 'SET_INNER_PADDING', payload: false });
@@ -258,12 +292,101 @@ const SiderBar = () => {
           }
           setSelectedKeys([key.itemKey]);
         }}
-        footer={
+      >
+        {/* Chat Section - Only show if there are chat items */}
+        {chatItems.length > 0 && (
           <>
+            {chatMenuItems.map((item) => {
+              if (item.items && item.items.length > 0) {
+                return (
+                  <Nav.Sub
+                    key={item.itemKey}
+                    itemKey={item.itemKey}
+                    text={item.text}
+                    icon={item.icon}
+                  >
+                    {item.items.map((subItem) => (
+                      <Nav.Item
+                        key={subItem.itemKey}
+                        itemKey={subItem.itemKey}
+                        text={subItem.text}
+                      />
+                    ))}
+                  </Nav.Sub>
+                );
+              } else {
+                return (
+                  <Nav.Item
+                    key={item.itemKey}
+                    itemKey={item.itemKey}
+                    text={item.text}
+                    icon={item.icon}
+                  />
+                );
+              }
+            })}
           </>
-        }
-      >
-        <Nav.Footer collapseButton={true}></Nav.Footer>
+        )}
+
+        {/* Divider */}
+        <Divider style={dividerStyle} />
+
+        {/* Workspace Section */}
+        {!isCollapsed && <div style={groupLabelStyle}>{t('控制台')}</div>}
+        {workspaceItems.map((item) => (
+          <Nav.Item
+            key={item.itemKey}
+            itemKey={item.itemKey}
+            text={item.text}
+            icon={item.icon}
+            className={item.className}
+          />
+        ))}
+
+        {/* Divider */}
+        <Divider style={dividerStyle} />
+
+        {/* Finance Management Section */}
+        {!isCollapsed && <div style={groupLabelStyle}>{t('个人中心')}</div>}
+        {financeItems.map((item) => (
+          <Nav.Item
+            key={item.itemKey}
+            itemKey={item.itemKey}
+            text={item.text}
+            icon={item.icon}
+            className={item.className}
+          />
+        ))}
+
+        {isAdmin() && (
+          <>
+            {/* Divider */}
+            <Divider style={dividerStyle} />
+
+            {/* Admin Section */}
+            {adminItems.map((item) => (
+              <Nav.Item
+                key={item.itemKey}
+                itemKey={item.itemKey}
+                text={item.text}
+                icon={item.icon}
+                className={item.className}
+              />
+            ))}
+          </>
+        )}
+
+        <Nav.Footer
+          collapseButton={true}
+          collapseText={(collapsed)=>
+            {
+              if(collapsed){
+                return t('展开侧边栏')
+              }
+                return t('收起侧边栏')
+            }
+          }
+        />
       </Nav>
     </>
   );

+ 5 - 2
web/src/i18n/locales/en.json

@@ -621,6 +621,7 @@
   "窗口等待": "window wait",
   "失败": "Failed",
   "绘图": "Drawing",
+  "绘图日志": "Drawing log",
   "放大": "Upscalers",
   "微妙放大": "Upscale (Subtle)",
   "创造放大": "Upscale (Creative)",
@@ -1120,7 +1121,7 @@
   "知识库 ID": "Knowledge Base ID",
   "请输入知识库 ID,例如:123456": "Please enter knowledge base ID, e.g.: 123456",
   "可选值": "Optional value",
-  "异步任务": "Async task",
+  "任务日志": "Task log",
   "你好": "Hello",
   "你好,请问有什么可以帮助您的吗?": "Hello, how may I help you?",
   "用户分组": "Your default group",
@@ -1335,5 +1336,7 @@
   "Claude思考适配 BudgetTokens = MaxTokens * BudgetTokens 百分比": "Claude thinking adaptation BudgetTokens = MaxTokens * BudgetTokens percentage",
   "思考适配 BudgetTokens 百分比": "Thinking adaptation BudgetTokens percentage",
   "0.1-1之间的小数": "Decimal between 0.1 and 1",
-  "模型相关设置": "Model related settings"
+  "模型相关设置": "Model related settings",
+  "收起侧边栏": "Collapse sidebar",
+  "展开侧边栏": "Expand sidebar"
 }

+ 2 - 0
web/src/pages/Setting/Model/SettingClaudeModel.js

@@ -18,6 +18,8 @@ const CLAUDE_HEADER = {
 
 const CLAUDE_DEFAULT_MAX_TOKENS = {
   'default': 8192,
+  "claude-3-haiku-20240307": 4096,
+  "claude-3-opus-20240229": 4096,
   'claude-3-7-sonnet-20250219-thinking': 8192,
 }
 

+ 1 - 4
web/src/pages/Setting/index.js

@@ -18,9 +18,6 @@ const Setting = () => {
   const [tabActiveKey, setTabActiveKey] = useState('1');
   let panes = [
     {
-      tab: t('个人设置'),
-      content: <PersonalSetting />,
-      itemKey: 'personal',
     },
   ];
 
@@ -61,7 +58,7 @@ const Setting = () => {
     if (tab) {
       setTabActiveKey(tab);
     } else {
-      onChangeTab('personal');
+      onChangeTab('operation');
     }
   }, [location.search]);
   return (