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
b94fe07a
Commit
b94fe07a
authored
Dec 11, 2025
by
Liu
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'test01' into test-tactics
# Conflicts: # src/pages/Home/HomeNew.tsx
parents
a7da634c
407bb3c3
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
90 additions
and
56 deletions
+90
-56
src/components/ChatEditor/index.tsx
+3
-3
src/layouts/HistoryBar/components/HistoryBarList/index.tsx
+0
-2
src/pages/Chat/Chat.tsx
+4
-20
src/pages/Home/HomeNew.tsx
+65
-29
src/pages/Home/components/QuestionList/QuestionList.tsx
+18
-2
No files found.
src/components/ChatEditor/index.tsx
View file @
b94fe07a
...
...
@@ -149,7 +149,8 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
const
storedToolId
=
safeSessionStorageGetItem
(
'currentToolId'
)
// 如果 currentToolId 是空字符串,视为 null,确保通用模式能正确高亮
setSessionToolId
(
storedToolId
&&
storedToolId
.
trim
()
?
storedToolId
:
null
)
},
[
toolIdFromUrl
])
// 当路由切换(如点击历史记录)时,同步最新的 sessionStorage,避免同标签页删除后状态不同步
},
[
toolIdFromUrl
,
location
.
pathname
])
const
startAnimation
=
()
=>
{
intervalRef
.
current
=
setInterval
(()
=>
{
...
...
@@ -403,10 +404,9 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
const
toolIdStr
=
String
(
tool
.
toolId
)
const
isSelectedByState
=
selectedToolId
&&
toolIdStr
===
String
(
selectedToolId
)
const
isSelectedBySession
=
!
selectedToolId
&&
sessionToolId
&&
toolIdStr
===
String
(
sessionToolId
)
const
isSelectedByUrl
=
!
selectedToolId
&&
!
sessionToolId
&&
toolIdFromUrl
&&
toolIdStr
===
String
(
toolIdFromUrl
)
// 通用模式高亮:路由内没有 toolId 或 toolId 为空时默认高亮,点击后也要高亮
const
isGeneralMode
=
tool
.
toolName
===
'通用模式'
&&
isToolBtnActive
&&
!
selectedToolId
&&
!
sessionToolId
&&
!
toolIdFromUrl
const
isSelected
=
isSelectedByState
||
isSelectedBySession
||
is
SelectedByUrl
||
is
GeneralMode
const
isSelected
=
isSelectedByState
||
isSelectedBySession
||
isGeneralMode
const
baseBtnClass
=
'w-auto h-[32px] px-3 rounded-full shadow-none text-[12px] flex items-center gap-2 transition-all duration-200 border'
...
...
src/layouts/HistoryBar/components/HistoryBarList/index.tsx
View file @
b94fe07a
...
...
@@ -33,8 +33,6 @@ export const HistoryBarList: React.FC<HistoryBarListProps> = ({ searchValue, onS
})
if
(
conversation
.
toolId
)
{
sessionStorage
.
setItem
(
'currentToolId'
,
conversation
.
toolId
)
// eslint-disable-next-line no-console
console
.
log
(
'889999999999:'
,
conversation
.
toolId
)
dispatch
(
setCurrentToolId
(
conversation
.
toolId
))
}
else
{
...
...
src/pages/Chat/Chat.tsx
View file @
b94fe07a
...
...
@@ -12,8 +12,7 @@ import { ChatEditor } from '@/components/ChatEditor'
import
type
{
ChatRecord
}
from
'@/types/chat'
import
{
fetchUserQaRecordPage
}
from
'@/api/conversation'
import
{
fetchCheckTokenApi
,
fetchStreamResponse
}
from
'@/api/chat'
import
{
fetchEfficiencyQuestionList
,
fetchToolList
}
from
'@/api/home'
// import { mockFetchToolList } from '@/api/mock/home'
import
{
fetchToolList
}
from
'@/api/home'
import
{
clearCurrentToolId
,
clearShouldSendQuestion
,
fetchConversations
,
setCurrentToolId
}
from
'@/store/conversationSlice'
import
{
getUserRolesForApi
}
from
'@/lib/utils'
import
type
{
RootState
}
from
'@/store'
...
...
@@ -93,23 +92,6 @@ export const Chat: React.FC = () => {
sessionToolId
:
null
,
})
// 首次进入 /chat/:id 时,拉取一次通用模式下的常见问题(toolId: ''),后续仍按现有逻辑走
useEffect
(()
=>
{
;(
async
()
=>
{
try
{
// 仅在本标签页首次进入时调用一次
if
(
sessionStorage
.
getItem
(
'__INITIAL_FAQ_LOADED__'
))
return
sessionStorage
.
setItem
(
'__INITIAL_FAQ_LOADED__'
,
'true'
)
const
sessionToolId
=
sessionStorage
.
getItem
(
'currentToolId'
)
||
''
await
fetchEfficiencyQuestionList
({
toolId
:
sessionToolId
})
}
catch
(
error
)
{
console
.
error
(
'初始化通用模式常见问题失败:'
,
error
)
}
})()
},
[])
// 进入聊天页时,同步当前链接和缓存中的 toolId 到页面上展示
useEffect
(()
=>
{
try
{
...
...
@@ -238,7 +220,9 @@ export const Chat: React.FC = () => {
/** 提交问题 */
const
handleSubmitQuestion
=
async
(
question
:
string
,
productCode
?:
string
,
toolId
?:
string
)
=>
{
const
resolvedToolId
=
toolId
??
currentToolId
??
undefined
// 优先读取缓存中的 toolId,再回退到传参或 Redux
const
sessionToolId
=
sessionStorage
.
getItem
(
'currentToolId'
)
??
undefined
const
resolvedToolId
=
toolId
??
sessionToolId
??
currentToolId
??
undefined
// 停止之前的请求
if
(
abortControllerRef
.
current
)
{
abortControllerRef
.
current
.
abort
()
...
...
src/pages/Home/HomeNew.tsx
View file @
b94fe07a
...
...
@@ -80,6 +80,42 @@ export const Home: React.FC = () => {
}
}
// 刷新问题列表
const
handleRefreshQuestions
=
useCallback
(
async
()
=>
{
// 先清空旧数据
setOtherQuestions
((
prev
:
any
)
=>
({
...
prev
,
content
:
[],
}))
setIsDataLoaded
(
false
)
// 重置加载状态
try
{
// 获取当前的 toolId,优先从 sessionStorage 获取,其次从 Redux 获取
const
sessionToolId
=
safeSessionStorageGetItem
(
'currentToolId'
)
||
''
const
searchParams
=
new
URLSearchParams
(
location
.
search
)
const
urlToolId
=
searchParams
.
get
(
'toolId'
)
||
''
const
finalToolId
=
sessionToolId
||
urlToolId
// 调用接口重新获取问题列表
const
res
=
await
fetchEfficiencyQuestionList
({
toolId
:
finalToolId
,
})
if
(
res
&&
res
.
data
&&
res
.
data
.
questions
)
{
setOtherQuestions
((
prev
:
any
)
=>
({
...
prev
,
content
:
res
.
data
.
questions
||
[],
}))
}
}
catch
(
error
)
{
console
.
error
(
'刷新问题列表失败:'
,
error
)
throw
error
// 抛出错误,让 QuestionList 组件处理
}
finally
{
setIsDataLoaded
(
true
)
// 无论成功失败都标记为已加载
}
},
[
location
.
search
])
// 处理工具按钮点击
const
requestIdRef
=
useRef
(
0
)
// 标记最新请求,避免旧响应覆盖
const
_handleToolClick
=
useCallback
(
async
(
isToolBtn
:
boolean
,
toolId
?:
string
,
ignoreUrlToolId
?:
boolean
)
=>
{
...
...
@@ -174,8 +210,26 @@ export const Home: React.FC = () => {
let
res
=
{}
as
any
if
(
viteOutputObj
===
'inner'
)
{
if
(
_loginCode
)
{
// 每次进入页面调用 sso_login 时,先清空 sessionStorage 中的 currentToolId
// 避免关闭标签页后再次打开时使用上次的历史 toolId
safeSessionStorageRemoveItem
(
'currentToolId'
)
res
=
await
fetchLoginByToken
(
_loginCode
)
if
(
res
.
data
)
{
// 登录成功后先打印完整的原始链接(删除之前)
// eslint-disable-next-line no-console
console
.
log
(
'登录成功,删除前完整链接:'
,
window
.
location
.
href
)
// 登录成功后先清理旧状态,避免沿用上一次的工具模式
dispatch
(
clearCurrentToolId
())
safeSessionStorageRemoveItem
(
'currentToolId'
)
const
currentUrl
=
new
URL
(
window
.
location
.
href
)
if
(
currentUrl
.
searchParams
.
has
(
'toolId'
))
{
currentUrl
.
searchParams
.
delete
(
'toolId'
)
// 使用 replace 避免产生新的历史记录
window
.
history
.
replaceState
({},
''
,
currentUrl
.
toString
())
}
// 删除后打印链接
// eslint-disable-next-line no-console
console
.
log
(
'登录成功,删除后完整链接:'
,
window
.
location
.
href
)
setToken
(
res
.
data
.
token
)
// 主动触发 storage 事件,确保其他组件能监听到变化
window
.
dispatchEvent
(
...
...
@@ -187,19 +241,7 @@ export const Home: React.FC = () => {
storageArea
:
localStorage
,
}),
)
// 登录成功后强制重置为通用模式:清除所有 toolId 相关状态
// 1. 清除 Redux 中的 currentToolId
dispatch
(
clearCurrentToolId
())
// 2. 清除 sessionStorage 中的 currentToolId
safeSessionStorageRemoveItem
(
'currentToolId'
)
// 3. 清除 URL 中的 toolId 参数(如果存在)
const
currentUrl
=
new
URL
(
window
.
location
.
href
)
if
(
currentUrl
.
searchParams
.
has
(
'toolId'
))
{
currentUrl
.
searchParams
.
delete
(
'toolId'
)
// 使用 replace 避免产生新的历史记录
window
.
history
.
replaceState
({},
''
,
currentUrl
.
toString
())
}
// 4. 触发自定义事件,通知 ChatEditor 强制重置为通用模式
// 触发自定义事件,通知 ChatEditor 强制重置为通用模式
window
.
dispatchEvent
(
new
CustomEvent
(
'forceResetToGeneralMode'
))
initConversation
()
dispatch
(
fetchConversations
())
...
...
@@ -214,6 +256,14 @@ export const Home: React.FC = () => {
// 模拟登录 可以用来测试
res
=
await
fetchLoginByUid
(
'123123'
)
if
(
res
.
data
)
{
// 登录成功后先清理旧状态,避免沿用上一次的工具模式
dispatch
(
clearCurrentToolId
())
safeSessionStorageRemoveItem
(
'currentToolId'
)
const
currentUrl
=
new
URL
(
window
.
location
.
href
)
if
(
currentUrl
.
searchParams
.
has
(
'toolId'
))
{
currentUrl
.
searchParams
.
delete
(
'toolId'
)
window
.
history
.
replaceState
({},
''
,
currentUrl
.
toString
())
}
setToken
(
res
.
data
.
token
)
// 主动触发 storage 事件,确保其他组件能监听到变化
window
.
dispatchEvent
(
...
...
@@ -225,18 +275,7 @@ export const Home: React.FC = () => {
storageArea
:
localStorage
,
}),
)
// 登录成功后强制重置为通用模式:清除所有 toolId 相关状态
// 1. 清除 Redux 中的 currentToolId
dispatch
(
clearCurrentToolId
())
// 2. 清除 sessionStorage 中的 currentToolId
safeSessionStorageRemoveItem
(
'currentToolId'
)
// 3. 清除 URL 中的 toolId 参数(如果存在)
const
currentUrl
=
new
URL
(
window
.
location
.
href
)
if
(
currentUrl
.
searchParams
.
has
(
'toolId'
))
{
currentUrl
.
searchParams
.
delete
(
'toolId'
)
window
.
history
.
replaceState
({},
''
,
currentUrl
.
toString
())
}
// 4. 触发自定义事件,通知 ChatEditor 强制重置为通用模式
// 触发自定义事件,通知 ChatEditor 强制重置为通用模式
window
.
dispatchEvent
(
new
CustomEvent
(
'forceResetToGeneralMode'
))
initConversation
()
dispatch
(
fetchConversations
())
...
...
@@ -290,8 +329,6 @@ export const Home: React.FC = () => {
)
}
<
div
className=
"w-full"
>
<
div
className=
"flex justify-center gap-[20px]"
>
{
!
isFromTactics
&&
(
<>
{
/* 左侧区域 - 产品问答和您可以试着问我 */
}
<
div
className=
"flex flex-col gap-[20px] items-center overflow-y-auto scrollbar-hide"
...
...
@@ -320,6 +357,7 @@ export const Home: React.FC = () => {
iconImg=
{
HomeIcon2
}
isToolBtn=
{
shouldChangeStyle
}
isLoaded=
{
isDataLoaded
}
onRefresh=
{
handleRefreshQuestions
}
/>
</
motion
.
div
>
{
shouldChangeStyle
&&
(
...
...
@@ -328,8 +366,6 @@ export const Home: React.FC = () => {
</
div
>
)
}
</
div
>
</>
)
}
{
/* 右侧区域 */
}
<
div
className=
"hidden sm:flex flex-1 h-full"
>
<
div
...
...
src/pages/Home/components/QuestionList/QuestionList.tsx
View file @
b94fe07a
...
...
@@ -22,6 +22,7 @@ interface QuestionListProps {
height
?:
string
isToolBtn
?:
boolean
isLoaded
?:
boolean
onRefresh
?:
()
=>
Promise
<
void
>
}
const
containerVariants
=
{
hidden
:
{},
...
...
@@ -69,6 +70,7 @@ const QuestionListBase: React.FC<QuestionListProps & WithAuthProps> = ({
displayCount
:
_displayCount
=
6
,
isToolBtn
=
false
,
isLoaded
=
false
,
onRefresh
,
})
=>
{
const
[
isRotating
,
setIsRotating
]
=
useState
(
false
)
const
[
displayedItems
,
setDisplayedItems
]
=
useState
<
string
[]
>
([])
...
...
@@ -85,11 +87,25 @@ const QuestionListBase: React.FC<QuestionListProps & WithAuthProps> = ({
setDisplayedItems
(
indices
.
map
(
index
=>
questions
[
index
]))
},
[
questions
,
actualDisplayCount
])
const
handleRefresh
=
()
=>
{
const
handleRefresh
=
async
()
=>
{
// 如果没有提供 onRefresh 回调,则不执行任何操作
if
(
!
onRefresh
)
{
return
}
setIsRotating
(
true
)
updateDisplayedItems
()
try
{
// 重新调用接口获取新问题
await
onRefresh
()
}
catch
(
error
)
{
console
.
error
(
'刷新问题列表失败:'
,
error
)
// 接口调用失败时不回退到随机选择,保持当前状态
}
finally
{
setIsRotating
(
false
)
}
}
const
handleClick
=
(
item
:
string
)
=>
{
if
(
checkAuth
()
&&
!
isClicking
)
{
setIsClicking
(
true
)
...
...
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