Selaa lähdekoodia

feat: Improve route handling and dynamic chat navigation in SiderBar

1808837298@qq.com 1 vuosi sitten
vanhempi
commit
2af05c166c
3 muutettua tiedostoa jossa 89 lisäystä ja 81 poistoa
  1. 24 28
      web/src/App.js
  2. 64 53
      web/src/components/SiderBar.js
  3. 1 0
      web/src/i18n/locales/en.json

+ 24 - 28
web/src/App.js

@@ -1,5 +1,5 @@
 import React, { lazy, Suspense, useContext, useEffect } from 'react';
 import React, { lazy, Suspense, useContext, useEffect } from 'react';
-import { Route, Routes } from 'react-router-dom';
+import { Route, Routes, useLocation } from 'react-router-dom';
 import Loading from './components/Loading';
 import Loading from './components/Loading';
 import User from './pages/User';
 import User from './pages/User';
 import { PrivateRoute } from './components/PrivateRoute';
 import { PrivateRoute } from './components/PrivateRoute';
@@ -8,10 +8,8 @@ import LoginForm from './components/LoginForm';
 import NotFound from './pages/NotFound';
 import NotFound from './pages/NotFound';
 import Setting from './pages/Setting';
 import Setting from './pages/Setting';
 import EditUser from './pages/User/EditUser';
 import EditUser from './pages/User/EditUser';
-import { getLogo, getSystemName } from './helpers';
 import PasswordResetForm from './components/PasswordResetForm';
 import PasswordResetForm from './components/PasswordResetForm';
 import PasswordResetConfirm from './components/PasswordResetConfirm';
 import PasswordResetConfirm from './components/PasswordResetConfirm';
-import { UserContext } from './context/User';
 import Channel from './pages/Channel';
 import Channel from './pages/Channel';
 import Token from './pages/Token';
 import Token from './pages/Token';
 import EditChannel from './pages/Channel/EditChannel';
 import EditChannel from './pages/Channel/EditChannel';
@@ -26,10 +24,6 @@ import Pricing from './pages/Pricing/index.js';
 import Task from "./pages/Task/index.js";
 import Task from "./pages/Task/index.js";
 import Playground from './pages/Playground/Playground.js';
 import Playground from './pages/Playground/Playground.js';
 import OAuth2Callback from "./components/OAuth2Callback.js";
 import OAuth2Callback from "./components/OAuth2Callback.js";
-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';
 import PersonalSetting from './components/PersonalSetting.js';
 
 
 const Home = lazy(() => import('./pages/Home'));
 const Home = lazy(() => import('./pages/Home'));
@@ -37,13 +31,15 @@ const Detail = lazy(() => import('./pages/Detail'));
 const About = lazy(() => import('./pages/About'));
 const About = lazy(() => import('./pages/About'));
 
 
 function App() {
 function App() {
+  const location = useLocation();
+  
   return (
   return (
     <>
     <>
       <Routes>
       <Routes>
         <Route
         <Route
           path='/'
           path='/'
           element={
           element={
-            <Suspense fallback={<Loading></Loading>}>
+            <Suspense fallback={<Loading></Loading>} key={location.pathname}>
               <Home />
               <Home />
             </Suspense>
             </Suspense>
           }
           }
@@ -59,7 +55,7 @@ function App() {
         <Route
         <Route
           path='/channel/edit/:id'
           path='/channel/edit/:id'
           element={
           element={
-            <Suspense fallback={<Loading></Loading>}>
+            <Suspense fallback={<Loading></Loading>} key={location.pathname}>
               <EditChannel />
               <EditChannel />
             </Suspense>
             </Suspense>
           }
           }
@@ -67,7 +63,7 @@ function App() {
         <Route
         <Route
           path='/channel/add'
           path='/channel/add'
           element={
           element={
-            <Suspense fallback={<Loading></Loading>}>
+            <Suspense fallback={<Loading></Loading>} key={location.pathname}>
               <EditChannel />
               <EditChannel />
             </Suspense>
             </Suspense>
           }
           }
@@ -107,7 +103,7 @@ function App() {
         <Route
         <Route
           path='/user/edit/:id'
           path='/user/edit/:id'
           element={
           element={
-            <Suspense fallback={<Loading></Loading>}>
+            <Suspense fallback={<Loading></Loading>} key={location.pathname}>
               <EditUser />
               <EditUser />
             </Suspense>
             </Suspense>
           }
           }
@@ -115,7 +111,7 @@ function App() {
         <Route
         <Route
           path='/user/edit'
           path='/user/edit'
           element={
           element={
-            <Suspense fallback={<Loading></Loading>}>
+            <Suspense fallback={<Loading></Loading>} key={location.pathname}>
               <EditUser />
               <EditUser />
             </Suspense>
             </Suspense>
           }
           }
@@ -123,7 +119,7 @@ function App() {
         <Route
         <Route
           path='/user/reset'
           path='/user/reset'
           element={
           element={
-            <Suspense fallback={<Loading></Loading>}>
+            <Suspense fallback={<Loading></Loading>} key={location.pathname}>
               <PasswordResetConfirm />
               <PasswordResetConfirm />
             </Suspense>
             </Suspense>
           }
           }
@@ -131,7 +127,7 @@ function App() {
         <Route
         <Route
           path='/login'
           path='/login'
           element={
           element={
-            <Suspense fallback={<Loading></Loading>}>
+            <Suspense fallback={<Loading></Loading>} key={location.pathname}>
               <LoginForm />
               <LoginForm />
             </Suspense>
             </Suspense>
           }
           }
@@ -139,7 +135,7 @@ function App() {
         <Route
         <Route
           path='/register'
           path='/register'
           element={
           element={
-            <Suspense fallback={<Loading></Loading>}>
+            <Suspense fallback={<Loading></Loading>} key={location.pathname}>
               <RegisterForm />
               <RegisterForm />
             </Suspense>
             </Suspense>
           }
           }
@@ -147,7 +143,7 @@ function App() {
         <Route
         <Route
           path='/reset'
           path='/reset'
           element={
           element={
-            <Suspense fallback={<Loading></Loading>}>
+            <Suspense fallback={<Loading></Loading>} key={location.pathname}>
               <PasswordResetForm />
               <PasswordResetForm />
             </Suspense>
             </Suspense>
           }
           }
@@ -155,7 +151,7 @@ function App() {
         <Route
         <Route
           path='/oauth/github'
           path='/oauth/github'
           element={
           element={
-            <Suspense fallback={<Loading></Loading>}>
+            <Suspense fallback={<Loading></Loading>} key={location.pathname}>
               <OAuth2Callback type='github'></OAuth2Callback>
               <OAuth2Callback type='github'></OAuth2Callback>
             </Suspense>
             </Suspense>
           }
           }
@@ -163,7 +159,7 @@ function App() {
         <Route
         <Route
           path='/oauth/linuxdo'
           path='/oauth/linuxdo'
           element={
           element={
-            <Suspense fallback={<Loading></Loading>}>
+            <Suspense fallback={<Loading></Loading>} key={location.pathname}>
                 <OAuth2Callback type='linuxdo'></OAuth2Callback>
                 <OAuth2Callback type='linuxdo'></OAuth2Callback>
             </Suspense>
             </Suspense>
           }
           }
@@ -172,7 +168,7 @@ function App() {
           path='/setting'
           path='/setting'
           element={
           element={
             <PrivateRoute>
             <PrivateRoute>
-              <Suspense fallback={<Loading></Loading>}>
+              <Suspense fallback={<Loading></Loading>} key={location.pathname}>
                 <Setting />
                 <Setting />
               </Suspense>
               </Suspense>
             </PrivateRoute>
             </PrivateRoute>
@@ -182,7 +178,7 @@ function App() {
           path='/personal'
           path='/personal'
           element={
           element={
             <PrivateRoute>
             <PrivateRoute>
-              <Suspense fallback={<Loading></Loading>}>
+              <Suspense fallback={<Loading></Loading>} key={location.pathname}>
                 <PersonalSetting />
                 <PersonalSetting />
               </Suspense>
               </Suspense>
             </PrivateRoute>
             </PrivateRoute>
@@ -192,7 +188,7 @@ function App() {
           path='/topup'
           path='/topup'
           element={
           element={
             <PrivateRoute>
             <PrivateRoute>
-              <Suspense fallback={<Loading></Loading>}>
+              <Suspense fallback={<Loading></Loading>} key={location.pathname}>
                 <TopUp />
                 <TopUp />
               </Suspense>
               </Suspense>
             </PrivateRoute>
             </PrivateRoute>
@@ -210,7 +206,7 @@ function App() {
           path='/detail'
           path='/detail'
           element={
           element={
             <PrivateRoute>
             <PrivateRoute>
-              <Suspense fallback={<Loading></Loading>}>
+              <Suspense fallback={<Loading></Loading>} key={location.pathname}>
                 <Detail />
                 <Detail />
               </Suspense>
               </Suspense>
             </PrivateRoute>
             </PrivateRoute>
@@ -220,7 +216,7 @@ function App() {
           path='/midjourney'
           path='/midjourney'
           element={
           element={
             <PrivateRoute>
             <PrivateRoute>
-              <Suspense fallback={<Loading></Loading>}>
+              <Suspense fallback={<Loading></Loading>} key={location.pathname}>
                 <Midjourney />
                 <Midjourney />
               </Suspense>
               </Suspense>
             </PrivateRoute>
             </PrivateRoute>
@@ -230,7 +226,7 @@ function App() {
           path='/task'
           path='/task'
           element={
           element={
             <PrivateRoute>
             <PrivateRoute>
-              <Suspense fallback={<Loading></Loading>}>
+              <Suspense fallback={<Loading></Loading>} key={location.pathname}>
                 <Task />
                 <Task />
               </Suspense>
               </Suspense>
             </PrivateRoute>
             </PrivateRoute>
@@ -239,7 +235,7 @@ function App() {
         <Route
         <Route
           path='/pricing'
           path='/pricing'
           element={
           element={
-            <Suspense fallback={<Loading></Loading>}>
+            <Suspense fallback={<Loading></Loading>} key={location.pathname}>
               <Pricing />
               <Pricing />
             </Suspense>
             </Suspense>
           }
           }
@@ -247,7 +243,7 @@ function App() {
         <Route
         <Route
           path='/about'
           path='/about'
           element={
           element={
-            <Suspense fallback={<Loading></Loading>}>
+            <Suspense fallback={<Loading></Loading>} key={location.pathname}>
               <About />
               <About />
             </Suspense>
             </Suspense>
           }
           }
@@ -255,7 +251,7 @@ function App() {
         <Route
         <Route
           path='/chat/:id?'
           path='/chat/:id?'
           element={
           element={
-            <Suspense fallback={<Loading></Loading>}>
+            <Suspense fallback={<Loading></Loading>} key={location.pathname}>
               <Chat />
               <Chat />
             </Suspense>
             </Suspense>
           }
           }
@@ -265,7 +261,7 @@ function App() {
             path='/chat2link'
             path='/chat2link'
             element={
             element={
               <PrivateRoute>
               <PrivateRoute>
-                <Suspense fallback={<Loading></Loading>}>
+                <Suspense fallback={<Loading></Loading>} key={location.pathname}>
                     <Chat2Link />
                     <Chat2Link />
                 </Suspense>
                 </Suspense>
               </PrivateRoute>
               </PrivateRoute>

+ 64 - 53
web/src/components/SiderBar.js

@@ -62,6 +62,25 @@ const iconStyle = (itemKey, selectedKeys) => {
   };
   };
 };
 };
 
 
+// Define routerMap as a constant outside the component
+const routerMap = {
+  home: '/',
+  channel: '/channel',
+  token: '/token',
+  redemption: '/redemption',
+  topup: '/topup',
+  user: '/user',
+  log: '/log',
+  midjourney: '/midjourney',
+  setting: '/setting',
+  about: '/about',
+  detail: '/detail',
+  pricing: '/pricing',
+  task: '/task',
+  playground: '/playground',
+  personal: '/personal',
+};
+
 const SiderBar = () => {
 const SiderBar = () => {
   const { t } = useTranslation();
   const { t } = useTranslation();
   const [styleState, styleDispatch] = useContext(StyleContext);
   const [styleState, styleDispatch] = useContext(StyleContext);
@@ -76,6 +95,7 @@ const SiderBar = () => {
   const theme = useTheme();
   const theme = useTheme();
   const setTheme = useSetTheme();
   const setTheme = useSetTheme();
   const location = useLocation();
   const location = useLocation();
+  const [routerMapState, setRouterMapState] = useState(routerMap);
 
 
   // 预先计算所有可能的图标样式
   // 预先计算所有可能的图标样式
   const allItemKeys = useMemo(() => {
   const allItemKeys = useMemo(() => {
@@ -97,25 +117,6 @@ const SiderBar = () => {
     return styles;
     return styles;
   }, [allItemKeys, selectedKeys]);
   }, [allItemKeys, selectedKeys]);
 
 
-  const routerMap = {
-    home: '/',
-    channel: '/channel',
-    token: '/token',
-    redemption: '/redemption',
-    topup: '/topup',
-    user: '/user',
-    log: '/log',
-    midjourney: '/midjourney',
-    setting: '/setting',
-    about: '/about',
-    chat: '/chat',
-    detail: '/detail',
-    pricing: '/pricing',
-    task: '/task',
-    playground: '/playground',
-    personal: '/personal',
-  };
-
   const workspaceItems = useMemo(
   const workspaceItems = useMemo(
     () => [
     () => [
       {
       {
@@ -237,21 +238,24 @@ const SiderBar = () => {
     [chatItems, t],
     [chatItems, t],
   );
   );
 
 
-  useEffect(() => {
-    const currentPath = location.pathname;
-    const matchingKey = Object.keys(routerMap).find(key => routerMap[key] === currentPath);
-
-    if (matchingKey) {
-      setSelectedKeys([matchingKey]);
-    } else if (currentPath.startsWith('/chat/')) {
-      setSelectedKeys(['chat']);
+  // Function to update router map with chat routes
+  const updateRouterMapWithChats = (chats) => {
+    const newRouterMap = { ...routerMap };
+    
+    if (Array.isArray(chats) && chats.length > 0) {
+      for (let i = 0; i < chats.length; i++) {
+        newRouterMap['chat' + i] = '/chat/' + i;
+      }
     }
     }
-  }, [location.pathname]);
+    
+    setRouterMapState(newRouterMap);
+    return newRouterMap;
+  };
 
 
+  // Update the useEffect for chat items
   useEffect(() => {
   useEffect(() => {
     let chats = localStorage.getItem('chats');
     let chats = localStorage.getItem('chats');
     if (chats) {
     if (chats) {
-      // console.log(chats);
       try {
       try {
         chats = JSON.parse(chats);
         chats = JSON.parse(chats);
         if (Array.isArray(chats)) {
         if (Array.isArray(chats)) {
@@ -263,19 +267,44 @@ const SiderBar = () => {
               chat.itemKey = 'chat' + i;
               chat.itemKey = 'chat' + i;
               chat.to = '/chat/' + i;
               chat.to = '/chat/' + i;
             }
             }
-            // setRouterMap({ ...routerMap, chat: '/chat/' + i })
             chatItems.push(chat);
             chatItems.push(chat);
           }
           }
           setChatItems(chatItems);
           setChatItems(chatItems);
+          
+          // Update router map with chat routes
+          updateRouterMapWithChats(chats);
         }
         }
       } catch (e) {
       } catch (e) {
         console.error(e);
         console.error(e);
         showError('聊天数据解析失败')
         showError('聊天数据解析失败')
       }
       }
     }
     }
+  }, []);
+
+  // Update the useEffect for route selection
+  useEffect(() => {
+    const currentPath = location.pathname;
+    let matchingKey = Object.keys(routerMapState).find(key => routerMapState[key] === currentPath);
+
+    // Handle chat routes
+    if (!matchingKey && currentPath.startsWith('/chat/')) {
+      const chatIndex = currentPath.split('/').pop();
+      if (!isNaN(chatIndex)) {
+        matchingKey = 'chat' + chatIndex;
+      } else {
+        matchingKey = 'chat';
+      }
+    }
 
 
+    // If we found a matching key, update the selected keys
+    if (matchingKey) {
+      setSelectedKeys([matchingKey]);
+    }
+  }, [location.pathname, routerMapState]);
+
+  useEffect(() => {
     setIsCollapsed(styleState.siderCollapsed);
     setIsCollapsed(styleState.siderCollapsed);
-  })
+  }, [styleState.siderCollapsed]);
 
 
   // Custom divider style
   // Custom divider style
   const dividerStyle = {
   const dividerStyle = {
@@ -322,14 +351,14 @@ const SiderBar = () => {
           // 确保在收起侧边栏时有选中的项目,避免不必要的计算
           // 确保在收起侧边栏时有选中的项目,避免不必要的计算
           if (selectedKeys.length === 0) {
           if (selectedKeys.length === 0) {
             const currentPath = location.pathname;
             const currentPath = location.pathname;
-            const matchingKey = Object.keys(routerMap).find(key => routerMap[key] === currentPath);
+            const matchingKey = Object.keys(routerMapState).find(key => routerMapState[key] === currentPath);
 
 
             if (matchingKey) {
             if (matchingKey) {
               setSelectedKeys([matchingKey]);
               setSelectedKeys([matchingKey]);
             } else if (currentPath.startsWith('/chat/')) {
             } else if (currentPath.startsWith('/chat/')) {
               setSelectedKeys(['chat']);
               setSelectedKeys(['chat']);
             } else {
             } else {
-              setSelectedKeys([]); // 默认选中首页
+              setSelectedKeys(['detail']); // 默认选中首页
             }
             }
           }
           }
         }}
         }}
@@ -338,28 +367,10 @@ const SiderBar = () => {
         hoverStyle={navItemHoverStyle}
         hoverStyle={navItemHoverStyle}
         selectedStyle={navItemSelectedStyle}
         selectedStyle={navItemSelectedStyle}
         renderWrapper={({ itemElement, isSubNav, isInSubNav, props }) => {
         renderWrapper={({ itemElement, isSubNav, isInSubNav, props }) => {
-          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 (
           return (
             <Link
             <Link
               style={{ textDecoration: 'none' }}
               style={{ textDecoration: 'none' }}
-              to={routerMap[props.itemKey]}
+              to={routerMapState[props.itemKey] || routerMap[props.itemKey]}
             >
             >
               {itemElement}
               {itemElement}
             </Link>
             </Link>
@@ -466,7 +477,7 @@ const SiderBar = () => {
 
 
         <Nav.Footer
         <Nav.Footer
           style={{
           style={{
-            paddingBottom: styleState?.isMobile ? '112px' : '20px',
+            paddingBottom: styleState?.isMobile ? '112px' : '',
           }}
           }}
           collapseButton={true}
           collapseButton={true}
           collapseText={(collapsed)=>
           collapseText={(collapsed)=>

+ 1 - 0
web/src/i18n/locales/en.json

@@ -1,5 +1,6 @@
 {
 {
   "主页": "Home",
   "主页": "Home",
+  "文档": "Docs",
   "控制台": "Console",
   "控制台": "Console",
   "$%.6f 额度": "$%.6f quota",
   "$%.6f 额度": "$%.6f quota",
   "%d 点额度": "%d point quota",
   "%d 点额度": "%d point quota",