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
0cfabedf
Commit
0cfabedf
authored
Dec 02, 2025
by
Liu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
更新聊天、首页和导航栏相关功能
parent
552559f6
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
246 additions
and
89 deletions
+246
-89
src/api/mock/conversation.ts
+4
-8
src/api/mock/home.ts
+56
-6
src/components/ChatEditor/index.tsx
+66
-42
src/layouts/HistoryBar/components/HistoryBarList/index.tsx
+5
-5
src/layouts/Navbar/Navbar.tsx
+7
-3
src/pages/Chat/Chat.tsx
+93
-23
src/pages/Home/HomeNew.tsx
+11
-2
src/store/conversationSlice.ts
+4
-0
No files found.
src/api/mock/conversation.ts
View file @
0cfabedf
/*
import
{
subDays
,
subMinutes
}
from
'date-fns'
import
type
{
Conversation
}
from
'@/types/conversation'
...
...
@@ -89,7 +88,7 @@ const conversationRecords: Conversation[] = [
}),
]
const conversationPageMockResponse: ConversationPageResponse = {
const
_
conversationPageMockResponse
:
ConversationPageResponse
=
{
code
:
'00000000'
,
message
:
'成功'
,
data
:
{
...
...
@@ -102,9 +101,6 @@ const conversationPageMockResponse: ConversationPageResponse = {
ok
:
true
,
}
export function mockFetchConversationPage() {
return Promise.resolve(conversationPageMockResponse)
}
*/
export
{}
// export function mockFetchConversationPage() {
// return Promise.resolve(conversationPageMockResponse)
// }
src/api/mock/home.ts
View file @
0cfabedf
/*
interface
EfficiencyQuestionResponse
{
code
:
string
message
:
string
...
...
@@ -8,7 +7,7 @@ interface EfficiencyQuestionResponse {
ok
:
boolean
}
const efficiencyQuestionMockResponse: EfficiencyQuestionResponse = {
const
_
efficiencyQuestionMockResponse
:
EfficiencyQuestionResponse
=
{
code
:
'00000000'
,
message
:
'成功'
,
data
:
{
...
...
@@ -26,9 +25,60 @@ const efficiencyQuestionMockResponse: EfficiencyQuestionResponse = {
ok
:
true
,
}
export function mockFetchEfficiencyQuestionList(): Promise<EfficiencyQuestionResponse> {
return Promise.resolve(efficiencyQuestionMockResponse)
// export function mockFetchEfficiencyQuestionList(): Promise<EfficiencyQuestionResponse> {
// return Promise.resolve(efficiencyQuestionMockResponse)
// }
interface
ToolListResponse
{
code
:
string
message
:
string
data
:
Array
<
{
toolId
:
string
toolName
:
string
toolContent
:
string
toolIcon
:
string
toolType
:
string
userRole
:
string
showOrder
:
number
}
>
ok
:
boolean
}
const
_toolListMockResponse
:
ToolListResponse
=
{
code
:
'00000000'
,
message
:
'成功'
,
data
:
[
{
toolId
:
'6712395743241'
,
toolName
:
'提质增效'
,
toolContent
:
'https://sit-wechat.guominpension.com/underwrite'
,
toolIcon
:
'http://p-cf-co-1255000025.cos.bj.csyun001.ccbcos.co/tool-increase.svg'
,
toolType
:
'03'
,
userRole
:
'02'
,
showOrder
:
8
,
},
{
toolId
:
'6712395743240'
,
toolName
:
'数据助手'
,
toolContent
:
'https://sit-wechat.guominpension.com/underwrite'
,
toolIcon
:
'http://p-cf-co-1255000025.cos.bj.csyun001.ccbcos.co/tool-data.svg'
,
toolType
:
'03'
,
userRole
:
'01'
,
showOrder
:
8
,
},
{
toolId
:
'general-mode'
,
toolName
:
'通用模式'
,
toolContent
:
'https://sit-wechat.guominpension.com/underwrite'
,
toolIcon
:
'http://p-cf-co-1255000025.cos.bj.csyun001.ccbcos.co/tool-normal.svg'
,
toolType
:
'01'
,
userRole
:
'00'
,
showOrder
:
8
,
},
],
ok
:
true
,
}
*/
export
{}
// export function mockFetchToolList(): Promise<ToolListResponse> {
// return Promise.resolve(toolListMockResponse)
// }
src/components/ChatEditor/index.tsx
View file @
0cfabedf
...
...
@@ -2,6 +2,7 @@ import React, { useEffect, useRef, useState } from 'react'
import
{
AnimatePresence
,
motion
}
from
'framer-motion'
import
{
Button
,
Tooltip
}
from
'@heroui/react'
import
{
useLocalStorageState
,
useToggle
}
from
'ahooks'
import
{
useSearchParams
}
from
'react-router-dom'
import
{
LoginModal
}
from
'../LoginModal'
import
type
{
RootState
}
from
'@/store'
import
SendIcon
from
'@/assets/svg/send.svg?react'
...
...
@@ -11,37 +12,35 @@ import { fetchToolList } from '@/api/home'
import
{
clearCurrentToolId
,
createConversation
,
setCurrentToolId
}
from
'@/store/conversationSlice'
import
{
getUserRolesForApi
}
from
'@/lib/utils'
/*
const MOCK_TOOL_LIST = [
{
toolId: '6712395743241',
toolName: '提质增效',
toolContent: 'https://sit-wechat.guominpension.com/underwrite',
toolIcon: 'http://p-cf-co-1255000025.cos.bj.csyun001.ccbcos.co/tool-increase.svg',
toolType: '03',
userRole: '02',
showOrder: 8,
},
{
toolId: '6712395743240',
toolName: '数据助手',
toolContent: 'https://sit-wechat.guominpension.com/underwrite',
toolIcon: 'http://p-cf-co-1255000025.cos.bj.csyun001.ccbcos.co/tool-data.svg',
toolType: '03',
userRole: '01',
showOrder: 8,
},
{
toolId: 'general-mode',
toolName: '通用模式',
toolContent: 'https://sit-wechat.guominpension.com/underwrite',
toolIcon: 'http://p-cf-co-1255000025.cos.bj.csyun001.ccbcos.co/tool-normal.svg',
toolType: '01',
userRole: '00',
showOrder: 8,
},
] as const
*/
// const MOCK_TOOL_LIST = [
// {
// toolId: '6712395743241',
// toolName: '提质增效',
// toolContent: 'https://sit-wechat.guominpension.com/underwrite',
// toolIcon: 'http://p-cf-co-1255000025.cos.bj.csyun001.ccbcos.co/tool-increase.svg',
// toolType: '03',
// userRole: '02',
// showOrder: 8,
// },
// {
// toolId: '6712395743240',
// toolName: '数据助手',
// toolContent: 'https://sit-wechat.guominpension.com/underwrite',
// toolIcon: 'http://p-cf-co-1255000025.cos.bj.csyun001.ccbcos.co/tool-data.svg',
// toolType: '03',
// userRole: '01',
// showOrder: 8,
// },
// {
// toolId: 'general-mode',
// toolName: '通用模式',
// toolContent: 'https://sit-wechat.guominpension.com/underwrite',
// toolIcon: 'http://p-cf-co-1255000025.cos.bj.csyun001.ccbcos.co/tool-normal.svg',
// toolType: '01',
// userRole: '00',
// showOrder: 8,
// },
// ] as const
interface
ChatEditorProps
{
onChange
?:
(
value
:
string
)
=>
void
...
...
@@ -68,11 +67,15 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
const
currentToolId
=
useAppSelector
((
state
:
RootState
)
=>
state
.
conversation
.
currentToolId
)
const
[
showToolQuestion
,
setShowToolQuestion
]
=
useState
<
boolean
>
(
false
)
const
[
sessionToolId
,
setSessionToolId
]
=
useState
<
string
|
null
>
(
null
)
const
[
searchParams
,
setSearchParams
]
=
useSearchParams
()
const
toolIdFromUrl
=
searchParams
.
get
(
'toolId'
)
// 获取工具列表
const
getToolList
=
async
()
=>
{
try
{
// 使用统一的方法获取 userRoles(先同步路由到 localStorage,然后读取)
// 使用 mock 数据(已注释)
// setToolList([...MOCK_TOOL_LIST])
// 真实API调用
const
userRoles
=
getUserRolesForApi
()
const
res
=
await
fetchToolList
({
userRoles
})
if
(
res
?.
data
)
{
...
...
@@ -98,28 +101,30 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
console
.
log
(
'[ChatEditor] currentToolId 或 sessionToolId 变化:'
,
{
currentToolId
,
sessionToolId
,
toolIdFromUrl
,
})
if
(
currentToolId
)
{
// eslint-disable-next-line no-console
console
.
log
(
'[ChatEditor] 高亮工具按钮:'
,
currentToolId
)
setSelectedToolId
(
currentToolId
)
setIsToolBtnActive
(
false
)
return
}
if
(
!
currentToolId
&&
sessionToolId
)
{
// eslint-disable-next-line no-console
console
.
log
(
'[ChatEditor] 使用 sessionToolId 恢复工具高亮:'
,
sessionToolId
)
if
(
sessionToolId
)
{
setSelectedToolId
(
sessionToolId
)
setIsToolBtnActive
(
false
)
return
}
// 如果 currentToolId 和 sessionToolId 都没有值,根据路由中的 toolId 来决定
if
(
toolIdFromUrl
)
{
setSelectedToolId
(
toolIdFromUrl
)
setIsToolBtnActive
(
false
)
}
else
{
// eslint-disable-next-line no-console
console
.
log
(
'[ChatEditor] 没有 currentToolId,回到通用模式'
)
setSelectedToolId
(
null
)
setIsToolBtnActive
(
true
)
}
},
[
currentToolId
,
sessionToolId
])
},
[
currentToolId
,
sessionToolId
,
toolIdFromUrl
])
// 监听 sessionStorage 中的 currentToolId(历史点击时写入)来辅助高亮逻辑
useEffect
(()
=>
{
...
...
@@ -134,6 +139,12 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
}
},
[])
// 当路由变化时,同步更新 sessionToolId(因为 storage 事件不会在同标签页触发)
useEffect
(()
=>
{
const
storedToolId
=
sessionStorage
.
getItem
(
'currentToolId'
)
setSessionToolId
(
storedToolId
)
},
[
toolIdFromUrl
])
const
startAnimation
=
()
=>
{
intervalRef
.
current
=
setInterval
(()
=>
{
setCurrentPlaceholder
(
prev
=>
(
prev
+
1
)
%
placeholders
.
length
)
...
...
@@ -215,6 +226,12 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
sessionStorage
.
removeItem
(
'currentToolId'
)
setSessionToolId
(
null
)
setShowToolQuestion
(
false
)
// 清空路由中的 toolId 参数
if
(
toolIdFromUrl
)
{
const
newSearchParams
=
new
URLSearchParams
(
searchParams
)
newSearchParams
.
delete
(
'toolId'
)
setSearchParams
(
newSearchParams
,
{
replace
:
true
})
}
try
{
await
dispatch
(
createConversation
({
conversationData
:
{},
...
...
@@ -382,8 +399,15 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
{
toolList
&&
toolList
.
length
>
0
&&
(
<
div
className=
"absolute left-4 bottom-2 flex items-center gap-3 pointer-events-auto pl-[16px]"
>
{
toolList
.
map
((
tool
:
any
,
index
:
number
)
=>
{
// tool.toolName === '通用模式' 的按钮(通用模式)在默认状态下高亮
const
isSelected
=
(
selectedToolId
===
tool
.
toolId
)
||
(
tool
.
toolName
===
'通用模式'
&&
isToolBtnActive
)
// 根据 selectedToolId 或路由中的 toolId 进行匹配,注意数据类型统一转换为字符串比较
// 优先使用 selectedToolId(用户点击后的状态),其次使用 sessionStorage 中的 currentToolId(刷新时使用),再次使用路由中的 toolId(初始化时使用)
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
||
isSelectedByUrl
||
isGeneralMode
// 调试打印
if
(
index
===
0
||
selectedToolId
===
tool
.
toolId
)
{
// eslint-disable-next-line no-console
...
...
src/layouts/HistoryBar/components/HistoryBarList/index.tsx
View file @
0cfabedf
...
...
@@ -32,21 +32,21 @@ export const HistoryBarList: React.FC<HistoryBarListProps> = ({ searchValue, onS
toolId
:
conversation
.
toolId
,
})
if
(
conversation
.
toolId
)
{
// 将当前会话的 toolId 写入 sessionStorage,供 ChatEditor 使用
sessionStorage
.
setItem
(
'currentToolId'
,
conversation
.
toolId
)
// eslint-disable-next-line no-console
console
.
log
(
'889999999999:'
,
conversation
.
toolId
)
dispatch
(
setCurrentToolId
(
conversation
.
toolId
))
}
else
{
// 没有 toolId 时,移除 session 中的记录
sessionStorage
.
removeItem
(
'currentToolId'
)
// eslint-disable-next-line no-console
console
.
log
(
'[HistoryBarList] 清除 toolId'
)
dispatch
(
clearCurrentToolId
())
}
// 直接导航到历史记录,不设置shouldSendQuestion
navigate
(
`/chat/
${
conversation
.
conversationId
}
`
,
{
// 在 URL 中拼接 toolId 作为查询参数,以便刷新页面后仍能保留
const
url
=
conversation
.
toolId
?
`/chat/
${
conversation
.
conversationId
}
?toolId=
${
conversation
.
toolId
}
`
:
`/chat/
${
conversation
.
conversationId
}
`
navigate
(
url
,
{
state
:
{
toolId
:
conversation
.
toolId
||
null
,
},
...
...
src/layouts/Navbar/Navbar.tsx
View file @
0cfabedf
...
...
@@ -22,7 +22,7 @@ const NavbarBase: React.FC<NavbarProps & WithAuthProps> = ({ isHistoryVisible, c
const
dispatch
=
useAppDispatch
()
const
navigate
=
useNavigate
()
const
{
currentConversationId
,
shouldNavigateToNewConversation
}
=
useAppSelector
(
state
=>
state
.
conversation
)
const
{
currentConversationId
,
shouldNavigateToNewConversation
,
currentToolId
}
=
useAppSelector
(
state
=>
state
.
conversation
)
const
handleCreateConversation
=
()
=>
{
dispatch
(
createConversation
({
...
...
@@ -103,10 +103,14 @@ const NavbarBase: React.FC<NavbarProps & WithAuthProps> = ({ isHistoryVisible, c
useEffect
(()
=>
{
if
(
shouldNavigateToNewConversation
&&
currentConversationId
)
{
navigate
(
`/chat/
${
currentConversationId
}
`
)
// 如果当前有选中的 toolId,在 URL 中拼接,以便刷新页面后保留工具选择
const
url
=
currentToolId
?
`/chat/
${
currentConversationId
}
?toolId=
${
currentToolId
}
`
:
`/chat/
${
currentConversationId
}
`
navigate
(
url
)
dispatch
(
clearNavigationFlag
())
}
},
[
shouldNavigateToNewConversation
,
currentConversationId
,
navigate
,
dispatch
])
},
[
shouldNavigateToNewConversation
,
currentConversationId
,
currentToolId
,
navigate
,
dispatch
])
// keep latest conversation id in sessionStorage for cross-page returns (e.g., from collect)
useEffect
(()
=>
{
...
...
src/pages/Chat/Chat.tsx
View file @
0cfabedf
import
React
,
{
useCallback
,
useEffect
,
useRef
,
useState
}
from
'react'
import
{
useLocation
,
useParams
}
from
'react-router-dom'
import
{
useLocation
,
useParams
,
useSearchParams
}
from
'react-router-dom'
import
{
Button
}
from
'@heroui/react'
import
{
motion
}
from
'framer-motion'
import
{
useScroll
}
from
'ahooks'
...
...
@@ -13,6 +13,7 @@ import type { ChatRecord } from '@/types/chat'
import
{
fetchUserQaRecordPage
}
from
'@/api/conversation'
import
{
fetchCheckTokenApi
,
fetchStreamResponse
}
from
'@/api/chat'
import
{
fetchToolList
}
from
'@/api/home'
// import { mockFetchToolList } from '@/api/mock/home'
import
{
clearCurrentToolId
,
clearShouldSendQuestion
,
fetchConversations
,
setCurrentToolId
}
from
'@/store/conversationSlice'
import
{
getUserRolesForApi
}
from
'@/lib/utils'
import
type
{
RootState
}
from
'@/store'
...
...
@@ -24,7 +25,21 @@ import SdreamLoading from '@/components/SdreamLoading'
export
const
Chat
:
React
.
FC
=
()
=>
{
const
{
id
}
=
useParams
<
{
id
:
string
}
>
()
const
location
=
useLocation
()
const
initialToolId
=
(
location
.
state
as
{
toolId
?:
string
|
null
}
|
null
)?.
toolId
const
[
searchParams
]
=
useSearchParams
()
// 优先从 URL 查询参数读取 toolId(刷新后仍能保留),其次从 location.state 读取
const
toolIdFromUrl
=
searchParams
.
get
(
'toolId'
)
// 添加调试日志,查看 location.state 的实际值
// eslint-disable-next-line no-console
console
.
log
(
'[Chat] location.state:'
,
location
.
state
)
const
toolIdFromState
=
(
location
.
state
as
{
toolId
?:
string
|
null
}
|
null
)?.
toolId
// 优先使用 URL 中的 toolId,其次使用 state 中的 toolId
const
initialToolId
=
toolIdFromUrl
!==
null
?
toolIdFromUrl
:
toolIdFromState
// eslint-disable-next-line no-console
console
.
log
(
'[Chat] initialToolId:'
,
{
fromUrl
:
toolIdFromUrl
,
fromState
:
toolIdFromState
,
final
:
initialToolId
,
})
const
[
isLoading
,
setIsLoading
]
=
useState
(
false
)
const
[
allItems
,
setAllItems
]
=
useState
<
ChatRecord
[]
>
([])
const
dispatch
=
useAppDispatch
()
...
...
@@ -35,13 +50,26 @@ export const Chat: React.FC = () => {
const
lastSentQuestionRef
=
useRef
<
string
>
(
''
)
const
abortControllerRef
=
useRef
<
AbortController
|
null
>
(
null
)
const
[
currentToolName
,
setCurrentToolName
]
=
useState
<
string
|
undefined
>
(
undefined
)
// 使用 ref 保存从 location.state 传递的 toolId,避免被异步操作覆盖
const
toolIdFromStateRef
=
useRef
<
string
|
null
|
undefined
>
(
undefined
)
// 历史记录点击时将 toolId 通过路由 state 传入,优先使用该值快速同步高亮
useEffect
(()
=>
{
// 保存从 location.state 传递的 toolId 到 ref
toolIdFromStateRef
.
current
=
initialToolId
if
(
typeof
initialToolId
===
'undefined'
)
return
if
(
initialToolId
)
{
dispatch
(
setCurrentToolId
(
initialToolId
))
// 统一转换为字符串,确保类型一致(真实API可能返回数字,需要转换为字符串)
const
normalizedToolId
=
String
(
initialToolId
)
// eslint-disable-next-line no-console
console
.
log
(
'[Chat] 从路由state设置toolId:'
,
{
originalToolId
:
initialToolId
,
originalType
:
typeof
initialToolId
,
normalizedToolId
,
normalizedType
:
typeof
normalizedToolId
,
})
dispatch
(
setCurrentToolId
(
normalizedToolId
))
}
else
{
dispatch
(
clearCurrentToolId
())
...
...
@@ -250,19 +278,56 @@ export const Chat: React.FC = () => {
// 如果 qaRecords 中没有 toolId,尝试从 conversations 中查找当前会话的 toolId(会话级别)
const
conversationToolId
=
latestToolId
||
(
conversations
.
find
(
conv
=>
conv
.
conversationId
===
conversationId
)?.
toolId
?.
trim
?.())
// 优先使用从 location.state 传递的 toolId(如果存在),这是从历史记录点击传递过来的
const
toolIdFromState
=
toolIdFromStateRef
.
current
!==
undefined
?
(
toolIdFromStateRef
.
current
?
String
(
toolIdFromStateRef
.
current
)
:
null
)
:
undefined
// eslint-disable-next-line no-console
console
.
log
(
'[Chat] 从历史记录获取 toolId:'
,
{
conversationId
,
toolIdFromState
,
latestToolIdFromQaRecords
:
latestToolId
,
conversationToolId
,
hasQaRecords
,
currentToolIdInRedux
:
currentToolId
,
})
// 确定最终使用的 toolId:优先使用 qaRecords 中的,其次使用 conversation 中的
const
finalToolId
=
latestToolId
||
conversationToolId
||
undefined
// 确定最终使用的 toolId:优先使用从 location.state 传递的,其次使用 qaRecords 中的,最后使用 conversation 中的
// 如果从 location.state 传递了 toolId,直接使用它(最高优先级)
if
(
toolIdFromState
!==
undefined
)
{
if
(
toolIdFromState
)
{
// 只有当 Redux 中的 toolId 与最终确定的 toolId 不一致时,才更新
if
(
currentToolId
!==
toolIdFromState
)
{
// eslint-disable-next-line no-console
console
.
log
(
'[Chat] 使用从路由state传递的 toolId:'
,
{
from
:
currentToolId
,
to
:
toolIdFromState
,
source
:
'location.state'
,
})
dispatch
(
setCurrentToolId
(
toolIdFromState
))
}
else
{
// eslint-disable-next-line no-console
console
.
log
(
'[Chat] toolId 已一致,无需更新:'
,
toolIdFromState
)
}
}
else
{
// 如果从 location.state 传递的是 null,清除 toolId
if
(
currentToolId
)
{
// eslint-disable-next-line no-console
console
.
log
(
'[Chat] 清除 toolId (从路由state传递null)'
)
dispatch
(
clearCurrentToolId
())
}
}
// 清除 ref,避免下次路由变化时误用
toolIdFromStateRef
.
current
=
undefined
}
else
{
// 如果没有从 location.state 传递 toolId(可能是嵌套路由传递失败),使用原来的逻辑
// 优先使用 qaRecords 中的 toolId,其次使用 conversation 中的 toolId
const
finalToolId
=
latestToolId
||
conversationToolId
||
undefined
if
(
hasQaRecords
||
conversationToolId
)
{
if
(
finalToolId
)
{
// 只有当 Redux 中的 toolId 与最终确定的 toolId 不一致时,才更新
if
(
currentToolId
!==
finalToolId
)
{
...
...
@@ -280,20 +345,19 @@ export const Chat: React.FC = () => {
}
}
else
{
// 如果 qaRecords 和 conversation 中都没有 toolId,清除 Redux 中的 toolId
if
(
currentToolId
)
{
// 如果 qaRecords 和 conversation 中都没有 toolId
// 如果有历史记录但没有 toolId,说明是通用模式,应该清除
if
(
hasQaRecords
&&
currentToolId
)
{
// eslint-disable-next-line no-console
console
.
log
(
'[Chat] 清除 toolId (qaRecords
和 conversation 中都没有
)'
)
console
.
log
(
'[Chat] 清除 toolId (qaRecords
中有记录但没有 toolId,通用模式
)'
)
dispatch
(
clearCurrentToolId
())
}
}
}
else
{
// 如果没有 qaRecords 且没有 conversation,清除 toolId
if
(
currentToolId
)
{
// eslint-disable-next-line no-console
console
.
log
(
'[Chat] 清除 toolId (没有历史记录)'
)
dispatch
(
clearCurrentToolId
())
// 如果没有历史记录,可能是新会话,但如果 Redux 中已经有 toolId(从 HistoryBarList 设置的),暂时保留
// 因为可能是刚点击历史记录但 API 还没返回,或者 location.state 传递失败但 Redux 中已有正确的值
else
if
(
!
hasQaRecords
&&
currentToolId
)
{
// eslint-disable-next-line no-console
console
.
log
(
'[Chat] 没有历史记录,保留 Redux 中的 toolId (可能是 location.state 传递失败):'
,
currentToolId
)
}
}
}
}
...
...
@@ -347,7 +411,9 @@ export const Chat: React.FC = () => {
const
getToolNameFromToolId
=
async
()
=>
{
if
(
currentToolId
)
{
try
{
// 使用统一的方法获取 userRoles(先同步路由到 localStorage,然后读取)
// 使用mock数据(已注释)
// const res = await mockFetchToolList()
// 真实API调用
const
userRoles
=
getUserRolesForApi
()
const
res
=
await
fetchToolList
({
userRoles
})
if
(
res
?.
data
)
{
...
...
@@ -414,12 +480,15 @@ export const Chat: React.FC = () => {
className=
{
`${styles.scrollable} scrollbar-hide scroll-smooth`
}
>
<
div
className=
{
styles
.
inter
}
>
{
allItems
.
map
((
record
,
index
)
=>
(
{
allItems
.
map
((
record
,
index
)
=>
{
const
recordId
=
record
.
answerList
?.[
0
]?.
recordId
||
record
.
groupId
const
uniqueKey
=
recordId
?
`${record.role}-${recordId}`
:
`${record.role}-${record.question || record.answerList?.[0]?.answer || ''}-${index}`
return
(
<
div
className=
"w-full chatItem mx-auto"
key=
{
`${record.role}-${index}-${
record.question || record.answerList?.[0]?.answer || ''
}`
}
key=
{
uniqueKey
}
>
{
record
.
role
===
'system'
&&
<
ChatWelcome
toolName=
{
currentToolName
}
/>
}
{
record
.
role
===
'user'
&&
<
ChatItemUser
record=
{
record
}
/>
}
...
...
@@ -433,7 +502,8 @@ export const Chat: React.FC = () => {
/>
)
}
</
div
>
))
}
)
})
}
</
div
>
</
motion
.
div
>
)
}
...
...
src/pages/Home/HomeNew.tsx
View file @
0cfabedf
...
...
@@ -87,7 +87,16 @@ export const Home: React.FC = () => {
}))
setIsDataLoaded
(
false
)
// 重置加载状态
try
{
const
res
=
await
fetchEfficiencyQuestionList
({
toolId
})
// 获取 toolId:优先使用传入参数,其次从 sessionStorage,再次从路由参数,都没有则使用空字符串
let
finalToolId
=
toolId
||
''
if
(
!
finalToolId
)
{
finalToolId
=
sessionStorage
.
getItem
(
'currentToolId'
)
||
''
}
if
(
!
finalToolId
)
{
const
searchParams
=
new
URLSearchParams
(
location
.
search
)
finalToolId
=
searchParams
.
get
(
'toolId'
)
||
''
}
const
res
=
await
fetchEfficiencyQuestionList
({
toolId
:
finalToolId
})
if
(
res
&&
res
.
data
&&
res
.
data
.
questions
)
{
setOtherQuestions
((
prev
:
any
)
=>
({
...
prev
,
...
...
@@ -105,7 +114,7 @@ export const Home: React.FC = () => {
// else if (isToolBtn) {
// setIsDataLoaded(true) // 恢复原始数据时标记为已加载
// }
},
[
originalOtherQuestions
])
},
[
originalOtherQuestions
,
location
.
search
])
// 监听工具按钮点击事件
useEffect
(()
=>
{
...
...
src/store/conversationSlice.ts
View file @
0cfabedf
...
...
@@ -3,6 +3,7 @@ import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
import
{
processConversationData
}
from
'./conversationSlice.helper'
import
type
{
Conversation
,
ConversationState
}
from
'@/types/conversation'
import
{
fetchCreateConversation
,
fetchDeleteUserConversation
,
fetchQueryUserConversationPage
}
from
'@/api/conversation'
// import { mockFetchConversationPage } from '@/api/mock/conversation'
const
initialState
:
ConversationState
=
{
conversations
:
[],
...
...
@@ -18,6 +19,9 @@ export const fetchConversations = createAsyncThunk(
'conversation/fetchConversations'
,
async
(
_
,
{
rejectWithValue
})
=>
{
try
{
// 使用mock数据(已注释)
// const response = await mockFetchConversationPage()
// 真实API调用
const
response
=
await
fetchQueryUserConversationPage
({
keyword
:
''
,
pageNum
:
0
,
...
...
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