Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
new-api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
f8bd6da8
authored
Mar 11, 2025
by
1808837298@qq.com
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: Improve route handling and dynamic chat navigation in SiderBar
parent
5c794a36
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
89 additions
and
81 deletions
+89
-81
web/src/App.js
+24
-28
web/src/components/SiderBar.js
+64
-53
web/src/i18n/locales/en.json
+1
-0
No files found.
web/src/App.js
View file @
f8bd6da8
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
>
...
...
web/src/components/SiderBar.js
View file @
f8bd6da8
...
...
@@ -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
(
routerMap
State
).
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
=
{
routerMap
State
[
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
)
=>
...
...
web/src/i18n/locales/en.json
View file @
f8bd6da8
{
"主页"
:
"Home"
,
"文档"
:
"Docs"
,
"控制台"
:
"Console"
,
"$%.6f 额度"
:
"$%.6f quota"
,
"%d 点额度"
:
"%d point quota"
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment