Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
S
sdream-ai-fe
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
侯明涛
sdream-ai-fe
Commits
a7da634c
Commit
a7da634c
authored
Dec 09, 2025
by
Liu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat:新建策略页面
parent
8a250ce8
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
239 additions
and
5 deletions
+239
-5
src/App.tsx
+20
-5
src/layouts/MainLayout/MainLayoutTactics.tsx
+96
-0
src/layouts/MainLayout/index.ts
+1
-0
src/layouts/Navbar/NavbarFrom.tsx
+122
-0
No files found.
src/App.tsx
View file @
a7da634c
import
'./App.css'
import
'./App.css'
import
React
from
'react'
import
React
from
'react'
import
{
BrowserRouter
as
Router
}
from
'react-router-dom'
import
{
BrowserRouter
as
Router
,
useLocation
}
from
'react-router-dom'
import
{
Provider
}
from
'react-redux'
import
{
Provider
}
from
'react-redux'
import
{
MainLayout
}
from
'./layouts'
import
{
MainLayout
,
MainLayoutTactics
}
from
'./layouts'
import
{
AppRoutes
}
from
'./routes/AppRoutes'
import
{
AppRoutes
}
from
'./routes/AppRoutes'
import
{
AuthProvider
}
from
'./auth/AuthContext'
import
{
AuthProvider
}
from
'./auth/AuthContext'
import
ToastWrapper
from
'./components/ToastWrapper/ToastWrapper'
import
ToastWrapper
from
'./components/ToastWrapper/ToastWrapper'
...
@@ -11,15 +11,30 @@ import { store } from './store'
...
@@ -11,15 +11,30 @@ import { store } from './store'
const
viteOutputObj
=
import
.
meta
.
env
.
VITE_OUTPUT_OBJ
||
'open'
const
viteOutputObj
=
import
.
meta
.
env
.
VITE_OUTPUT_OBJ
||
'open'
const
basename
=
viteOutputObj
===
'inner'
?
'/sdream-fe'
:
'/sdream-ai'
const
basename
=
viteOutputObj
===
'inner'
?
'/sdream-fe'
:
'/sdream-ai'
const
LayoutSwitcher
:
React
.
FC
=
()
=>
{
const
location
=
useLocation
()
const
isFromTactics
=
new
URLSearchParams
(
location
.
search
).
get
(
'from'
)
===
'tactics'
if
(
isFromTactics
)
{
return
(
<
MainLayoutTactics
>
<
AppRoutes
/>
</
MainLayoutTactics
>
)
}
return
(
<
MainLayout
>
<
AppRoutes
/>
</
MainLayout
>
)
}
const
App
:
React
.
FC
=
()
=>
{
const
App
:
React
.
FC
=
()
=>
{
return
(
return
(
<
Provider
store=
{
store
}
>
<
Provider
store=
{
store
}
>
<
ToastWrapper
>
<
ToastWrapper
>
<
AuthProvider
>
<
AuthProvider
>
<
Router
basename=
{
basename
}
>
<
Router
basename=
{
basename
}
>
<
MainLayout
>
<
LayoutSwitcher
/>
<
AppRoutes
/>
</
MainLayout
>
</
Router
>
</
Router
>
</
AuthProvider
>
</
AuthProvider
>
</
ToastWrapper
>
</
ToastWrapper
>
...
...
src/layouts/MainLayout/MainLayoutTactics.tsx
0 → 100644
View file @
a7da634c
import
type
React
from
'react'
import
{
motion
}
from
'framer-motion'
import
{
useEffect
,
useState
}
from
'react'
import
{
useLocation
}
from
'react-router-dom'
import
{
useSessionStorageState
}
from
'ahooks'
import
styles
from
'./MainLayout.module.less'
import
{
useAuth
}
from
'@/auth/AuthContext'
import
{
LoginModal
}
from
'@/components/LoginModal'
import
MingcuteArrowsRightFill
from
'@/assets/svg/MingcuteArrowsRightFill.svg?react'
import
{
isMobile
}
from
'@/utils'
import
{
useAppDispatch
}
from
'@/store/hook'
import
{
fetchConversations
}
from
'@/store/conversationSlice'
interface
MainLayoutTacticsProps
{
children
:
React
.
ReactNode
}
const
contentVariants
=
{
navTween
:
{
x
:
'-90px'
,
transition
:
{
type
:
'tween'
,
duration
:
0.3
,
ease
:
'easeInOut'
},
},
mainTween
:
{
x
:
'-60px'
,
transition
:
{
type
:
'tween'
,
duration
:
0.3
,
ease
:
'easeInOut'
},
},
expanded
:
{
width
:
'90px'
,
x
:
0
,
transition
:
{
type
:
'spring'
,
stiffness
:
300
,
damping
:
30
},
},
shrunk
:
{
width
:
isMobile
()
?
'90px'
:
'340px'
,
x
:
0
,
transition
:
{
type
:
'spring'
,
stiffness
:
300
,
damping
:
30
},
},
}
export
const
MainLayoutTactics
:
React
.
FC
<
MainLayoutTacticsProps
>
=
({
children
})
=>
{
const
{
showLoginModal
,
toggleLoginModal
}
=
useAuth
()
const
[
isHistoryVisible
,
setHistoryVisible
]
=
useState
(
false
)
const
location
=
useLocation
()
const
dispatch
=
useAppDispatch
()
const
[
navBarVisibleLocal
]
=
useSessionStorageState
<
string
|
undefined
>
(
'__NAV_BAR_VISIBLE_LOCAL__'
,
{
defaultValue
:
'0'
,
listenStorageChange
:
true
,
},
)
useEffect
(()
=>
{
dispatch
(
fetchConversations
())
},
[
dispatch
])
useEffect
(()
=>
{
if
(
location
.
pathname
===
'/tools'
||
location
.
pathname
===
'/collect'
)
{
setHistoryVisible
(
false
)
}
},
[
location
.
pathname
])
return
(
<
motion
.
main
className=
{
styles
.
layoutMain
}
>
<
motion
.
div
animate=
{
navBarVisibleLocal
===
'0'
?
isHistoryVisible
?
'shrunk'
:
'expanded'
:
'navTween'
}
variants=
{
contentVariants
}
className=
{
`fixed right-[-12px] top-[10px] z-[49] h-auto sm:relative flex sm:h-full items-center ${isHistoryVisible && !isMobile() ? 'w-[340px]' : 'w-[90px]'} box-border`
}
>
{
!
isHistoryVisible
&&
(
<
motion
.
div
initial=
"hidden"
animate=
"visible"
variants=
{
{
hidden
:
{
x
:
-
5
,
opacity
:
0
,
},
}
}
className=
{
`${styles.sidebarArrow} side-bar-arrow h-[42px] flex items-center`
}
>
<
MingcuteArrowsRightFill
className=
"text-[#818d91]"
/>
</
motion
.
div
>
)
}
</
motion
.
div
>
<
motion
.
div
variants=
{
contentVariants
}
animate=
{
navBarVisibleLocal
===
'0'
?
''
:
'mainTween'
}
className=
{
`${styles.layoutContent} px-[12px]`
}
>
{
children
}
</
motion
.
div
>
<
LoginModal
isOpen=
{
showLoginModal
}
onClose=
{
toggleLoginModal
}
/>
</
motion
.
main
>
)
}
src/layouts/MainLayout/index.ts
View file @
a7da634c
export
{
MainLayout
}
from
'./MainLayout'
export
{
MainLayout
}
from
'./MainLayout'
export
{
MainLayoutTactics
}
from
'./MainLayoutTactics'
src/layouts/Navbar/NavbarFrom.tsx
0 → 100644
View file @
a7da634c
import
type
React
from
'react'
import
{
motion
}
from
'framer-motion'
import
{
useEffect
,
useRef
,
useState
}
from
'react'
import
{
useNavigate
}
from
'react-router-dom'
import
{
useClickAway
,
useSessionStorageState
}
from
'ahooks'
import
styles
from
'./Navbar.module.less'
import
{
NavBarItem
}
from
'./components/NavBarItem'
import
{
clearNavigationFlag
,
createConversation
}
from
'@/store/conversationSlice'
import
type
{
WithAuthProps
}
from
'@/auth/withAuth'
import
{
withAuth
}
from
'@/auth/withAuth'
import
{
NAV_BAR_ITEMS
}
from
'@/config/nav'
import
{
useAppDispatch
,
useAppSelector
}
from
'@/store/hook'
import
{
isMobile
}
from
'@/utils'
interface
NavbarProps
{
isHistoryVisible
:
boolean
onSetHistoryVisible
:
(
visible
:
boolean
)
=>
void
}
const
NavbarFromBase
:
React
.
FC
<
NavbarProps
&
WithAuthProps
>
=
({
isHistoryVisible
,
checkAuth
,
onSetHistoryVisible
})
=>
{
const
dispatch
=
useAppDispatch
()
const
navigate
=
useNavigate
()
const
{
currentConversationId
,
shouldNavigateToNewConversation
,
currentToolId
}
=
useAppSelector
(
state
=>
state
.
conversation
)
const
handleCreateConversation
=
()
=>
{
dispatch
(
createConversation
({
conversationData
:
{},
shouldNavigate
:
true
,
shouldSendQuestion
:
''
,
}))
}
const
[
isH5NavVisible
,
setIsH5NavVisible
]
=
useState
(
isMobile
())
const
handleClick
=
(
type
:
string
|
undefined
)
=>
{
if
(
type
===
'logo'
)
{
if
(
!
isH5NavVisible
)
{
navigate
(
'/'
)
setIsH5NavVisible
(
true
)
}
else
{
setIsH5NavVisible
(
!
isH5NavVisible
)
}
return
}
setIsH5NavVisible
(
true
)
if
(
!
checkAuth
())
{
return
}
if
(
type
===
'add'
)
{
if
(
location
.
pathname
.
includes
(
'/chat'
))
{
handleCreateConversation
()
}
else
{
navigate
(
'/'
)
}
onSetHistoryVisible
(
false
)
}
if
(
type
===
'history'
)
{
onSetHistoryVisible
(
!
isHistoryVisible
)
}
}
const
[
navBarVisibleLocal
,
setNavBarVisibleLocal
]
=
useSessionStorageState
<
string
|
undefined
>
(
'__NAV_BAR_VISIBLE_LOCAL__'
,
{
defaultValue
:
'0'
,
listenStorageChange
:
true
,
},
)
const
toggleNavBarVisible
=
()
=>
{
setNavBarVisibleLocal
(
navBarVisibleLocal
===
'1'
?
'0'
:
'1'
)
}
useEffect
(()
=>
{
if
(
shouldNavigateToNewConversation
&&
currentConversationId
)
{
const
url
=
currentToolId
?
`/chat/
${
currentConversationId
}
?toolId=
${
currentToolId
}
`
:
`/chat/
${
currentConversationId
}
`
navigate
(
url
,
{
state
:
{
toolId
:
currentToolId
||
null
,
},
})
dispatch
(
clearNavigationFlag
())
}
},
[
shouldNavigateToNewConversation
,
currentConversationId
,
currentToolId
,
navigate
,
dispatch
])
useEffect
(()
=>
{
if
(
currentConversationId
)
{
sessionStorage
.
setItem
(
'currentConversationId'
,
currentConversationId
)
}
},
[
currentConversationId
])
const
navRef
=
useRef
<
HTMLButtonElement
>
(
null
)
useClickAway
(()
=>
{
setIsH5NavVisible
(
true
)
},
navRef
)
return
(
<
motion
.
nav
ref=
{
navRef
}
animate=
{
navBarVisibleLocal
===
'0'
?
'hidden'
:
''
}
className=
"h-full flex-shrink-0 flex flex-col items-center justify-center relative"
>
<
motion
.
div
className=
{
`layoutNavBarJoyride ${styles.layoutNavBarAgent} rounded-full ${isH5NavVisible ? 'h-[55px] bg-white/70 shadow-md' : 'h-[380px]'} w-[54px] overflow-hidden py-[8px] sm:w-[64px] sm:bg-white gap-[24px] sm:h-auto sm:rounded-3xl sm:flex sm:py-[24px] sm:px-[8px]`
}
>
{
NAV_BAR_ITEMS
.
map
((
item
)
=>
{
return
(
<
NavBarItem
isHistoryVisible=
{
isHistoryVisible
}
onClick=
{
handleClick
}
icon=
{
item
.
icon
}
label=
{
item
.
label
}
key=
{
item
.
key
}
type=
{
item
.
key
}
/>
)
})
}
</
motion
.
div
>
<
div
onClick=
{
toggleNavBarVisible
}
className=
{
`${styles.sidebarAction} ${navBarVisibleLocal === '0' ? styles.open : ''}`
}
></
div
>
</
motion
.
nav
>
)
}
export
const
NavbarFrom
=
withAuth
(
NavbarFromBase
)
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