feat: Improve route handling and dynamic chat navigation in SiderBar

This commit is contained in:
1808837298@qq.com
2025-03-11 14:55:48 +08:00
parent 69db1f1465
commit 2af05c166c
3 changed files with 89 additions and 81 deletions

View File

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

View File

@@ -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 { t } = useTranslation();
const [styleState, styleDispatch] = useContext(StyleContext);
@@ -76,6 +95,7 @@ const SiderBar = () => {
const theme = useTheme();
const setTheme = useSetTheme();
const location = useLocation();
const [routerMapState, setRouterMapState] = useState(routerMap);
// 预先计算所有可能的图标样式
const allItemKeys = useMemo(() => {
@@ -97,25 +117,6 @@ const SiderBar = () => {
return styles;
}, [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(
() => [
{
@@ -237,21 +238,24 @@ const SiderBar = () => {
[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(() => {
let chats = localStorage.getItem('chats');
if (chats) {
// console.log(chats);
try {
chats = JSON.parse(chats);
if (Array.isArray(chats)) {
@@ -263,19 +267,44 @@ const SiderBar = () => {
chat.itemKey = 'chat' + i;
chat.to = '/chat/' + i;
}
// setRouterMap({ ...routerMap, chat: '/chat/' + i })
chatItems.push(chat);
}
setChatItems(chatItems);
// Update router map with chat routes
updateRouterMapWithChats(chats);
}
} catch (e) {
console.error(e);
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);
})
}, [styleState.siderCollapsed]);
// Custom divider style
const dividerStyle = {
@@ -322,14 +351,14 @@ const SiderBar = () => {
// 确保在收起侧边栏时有选中的项目,避免不必要的计算
if (selectedKeys.length === 0) {
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) {
setSelectedKeys([matchingKey]);
} else if (currentPath.startsWith('/chat/')) {
setSelectedKeys(['chat']);
} else {
setSelectedKeys([]); // 默认选中首页
setSelectedKeys(['detail']); // 默认选中首页
}
}
}}
@@ -338,28 +367,10 @@ const SiderBar = () => {
hoverStyle={navItemHoverStyle}
selectedStyle={navItemSelectedStyle}
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 (
<Link
style={{ textDecoration: 'none' }}
to={routerMap[props.itemKey]}
to={routerMapState[props.itemKey] || routerMap[props.itemKey]}
>
{itemElement}
</Link>
@@ -466,7 +477,7 @@ const SiderBar = () => {
<Nav.Footer
style={{
paddingBottom: styleState?.isMobile ? '112px' : '20px',
paddingBottom: styleState?.isMobile ? '112px' : '',
}}
collapseButton={true}
collapseText={(collapsed)=>

View File

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