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
8c98a5a1
Commit
8c98a5a1
authored
Apr 14, 2026
by
Liu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix:点击各按钮时传参高亮展示存入toolID
parent
57f63bd8
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
285 additions
and
134 deletions
+285
-134
a.txt
+24
-0
src/api/conversation.ts
+20
-4
src/components/ChatEditor/index.tsx
+67
-64
src/hooks/useBusinessInsightWorkflow.ts
+119
-0
src/pages/Chat/Chat.tsx
+41
-8
src/pages/Chat/components/ChatItem/ChatAnswerRecommend.tsx
+1
-0
src/pages/Home/HomeNew.tsx
+13
-58
No files found.
a.txt
0 → 100644
View file @
8c98a5a1
业务洞察最新工作流逻辑
第一步问问题 点击业务洞察按钮【开启主工作流】
会返回workflowSessionId
第二步问问题 拿主工作流返回的workflowSessionId,recordType:A12和输入的问题继续调用提问接口【提问主工作流】
会返回开启子工作流需要的answer
answer不为json:正常提问
answer为json:返回子工作流recordType,question
第三步问问题 拿第二步返回的recordType【开启子工作流】
返回workflowSessionId,cardList
判断cardList是否为空,是否展示输入框
第四步问问题 拿第三步返回的cardList【提问子工作流】
cardList为空,则正常传question和recordType和子工作流workflowSessionId,不传paramMap
cardList不为空,则传recordType,展示输入框填入参数后添加到paramMap中和子工作流workflowSessionId传给提问接口
子工作流返回:子工作流answer内end=true时跳出子工作流,recordType:A12再次开启主工作流,此时清空paramMap
若是正常回答完成后开启主工作流不需要传question
若子工作流回答不了的情况下需要带着answer.question提问主工作流
src/api/conversation.ts
View file @
8c98a5a1
...
@@ -39,14 +39,30 @@ export function fetchDeleteUserConversation(conversationIdList: string[]) {
...
@@ -39,14 +39,30 @@ export function fetchDeleteUserConversation(conversationIdList: string[]) {
* 获取历史会话ID
* 获取历史会话ID
* @params
* @params
*/
*/
export
function
fetchSessionConversationId
<
T
>
(
data
:
T
)
{
export
async
function
fetchSessionConversationId
<
T
>
(
data
:
T
)
{
const
payload
=
(
data
||
{})
as
Record
<
string
,
any
>
const
payload
=
(
data
||
{})
as
Record
<
string
,
any
>
const
sessionToolId
=
safeSessionStorageGetItem
(
'currentToolId'
)
||
''
// 首次进入时 `currentToolId` 可能还没被 `ChatEditor` 写入 sessionStorage。
// 这里做一个极短轮询,避免第一次请求 `toolId/busiId` 读到空字符串。
let
sessionToolId
=
safeSessionStorageGetItem
(
'currentToolId'
)
||
''
if
(
!
sessionToolId
)
{
const
maxWaitMs
=
600
const
intervalMs
=
100
const
start
=
Date
.
now
()
while
(
Date
.
now
()
-
start
<
maxWaitMs
)
{
await
new
Promise
(
resolve
=>
setTimeout
(
resolve
,
intervalMs
))
sessionToolId
=
safeSessionStorageGetItem
(
'currentToolId'
)
||
''
if
(
sessionToolId
)
{
break
}
}
}
const
requestData
=
{
const
requestData
=
{
...
payload
,
...
payload
,
busiType
:
'01'
,
busiType
:
'01'
,
busiId
:
sessionToolId
||
payload
?.
busiId
||
''
,
busiId
:
sessionToolId
,
toolId
:
sessionToolId
||
payload
?.
toolId
||
''
,
toolId
:
sessionToolId
,
}
}
return
http
.
post
(
'/conversation/api/conversation/mobile/v1/get_user_conversation_session'
,
requestData
)
return
http
.
post
(
'/conversation/api/conversation/mobile/v1/get_user_conversation_session'
,
requestData
)
}
}
src/components/ChatEditor/index.tsx
View file @
8c98a5a1
...
@@ -36,7 +36,7 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
...
@@ -36,7 +36,7 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
const
isAsking
=
useAppSelector
((
state
:
RootState
)
=>
state
.
chat
.
isAsking
)
const
isAsking
=
useAppSelector
((
state
:
RootState
)
=>
state
.
chat
.
isAsking
)
const
[
toolList
,
setToolList
]
=
useState
<
any
[]
>
([])
const
[
toolList
,
setToolList
]
=
useState
<
any
[]
>
([])
const
[
selectedToolId
,
setSelectedToolId
]
=
useState
<
string
|
null
>
(
null
)
const
[
selectedToolId
,
setSelectedToolId
]
=
useState
<
string
|
null
>
(
null
)
const
[
isToolBtnActive
,
setIsToolBtnActive
]
=
useState
<
boolean
>
(
true
)
const
[
_
isToolBtnActive
,
setIsToolBtnActive
]
=
useState
<
boolean
>
(
true
)
const
currentToolId
=
useAppSelector
((
state
:
RootState
)
=>
state
.
conversation
.
currentToolId
)
const
currentToolId
=
useAppSelector
((
state
:
RootState
)
=>
state
.
conversation
.
currentToolId
)
const
[
showToolQuestion
,
setShowToolQuestion
]
=
useState
<
boolean
>
(
false
)
const
[
showToolQuestion
,
setShowToolQuestion
]
=
useState
<
boolean
>
(
false
)
const
[
sessionToolId
,
setSessionToolId
]
=
useState
<
string
|
null
>
(
null
)
const
[
sessionToolId
,
setSessionToolId
]
=
useState
<
string
|
null
>
(
null
)
...
@@ -146,12 +146,17 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
...
@@ -146,12 +146,17 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
})
})
if
(
res
?.
data
&&
Array
.
isArray
(
res
.
data
)
&&
res
.
data
.
length
>
0
)
{
if
(
res
?.
data
&&
Array
.
isArray
(
res
.
data
)
&&
res
.
data
.
length
>
0
)
{
setToolList
(
res
.
data
)
setToolList
(
res
.
data
)
// 仅在“没有任何持久来源”时,才写入默认工具,避免覆盖已有的会话 toolId
const
storedToolId
=
safeSessionStorageGetItem
(
'currentToolId'
)
const
hasAnyToolSource
=
Boolean
(
storedToolId
||
currentToolId
||
toolIdFromUrl
)
if
(
!
hasAnyToolSource
)
{
// 存入第0个工具信息到缓存
// 存入第0个工具信息到缓存
const
defaultTool
=
res
.
data
[
0
]
const
defaultTool
=
res
.
data
[
0
]
safeSessionStorageSetItem
(
'currentToolId'
,
defaultTool
.
toolId
)
safeSessionStorageSetItem
(
'currentToolId'
,
defaultTool
.
toolId
)
safeSessionStorageSetItem
(
'currentToolName'
,
defaultTool
.
toolName
)
safeSessionStorageSetItem
(
'currentToolName'
,
defaultTool
.
toolName
)
}
}
}
}
}
catch
(
error
)
{
catch
(
error
)
{
console
.
error
(
'获取工具列表失败:'
,
error
)
console
.
error
(
'获取工具列表失败:'
,
error
)
}
}
...
@@ -160,25 +165,20 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
...
@@ -160,25 +165,20 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
// 根据 currentToolId 以及 sessionStorage 中的记录决定高亮逻辑
// 根据 currentToolId 以及 sessionStorage 中的记录决定高亮逻辑
useEffect
(()
=>
{
useEffect
(()
=>
{
console
.
log
(
'[chat-toolid-log] ChatEditor currentToolId:'
,
currentToolId
,
'| sessionToolId:'
,
sessionToolId
,
'| fromCollect:'
,
fromCollect
)
console
.
log
(
'[chat-toolid-log] ChatEditor currentToolId:'
,
currentToolId
,
'| sessionToolId:'
,
sessionToolId
,
'| fromCollect:'
,
fromCollect
)
// 关键修复:首次进入/切换路由时,Redux 里的 toolId 可能先到,但 sessionToolId 还没同步。
// 此时不应该“清空 Redux / 写空缓存”,而是用 Redux 回填 sessionStorage,避免出现“高亮有值但缓存为空”。
if
(
currentToolId
&&
!
sessionToolId
&&
!
fromCollect
)
{
if
(
currentToolId
&&
!
sessionToolId
&&
!
fromCollect
)
{
// 清除过期的 Redux 值
setSelectedToolId
(
currentToolId
)
dispatch
(
clearCurrentToolId
())
setIsToolBtnActive
(
false
)
console
.
log
(
'[chat-toolid-log] ChatEditor 清除 Redux - 逻辑三 - line:155'
)
// 用 Redux 回填缓存,确保后续接口/其他组件读取到一致的 toolId
// 如果 URL 中还有 toolId,也清除它
safeSessionStorageSetItem
(
'currentToolId'
,
String
(
currentToolId
))
if
(
toolIdFromUrl
)
{
const
newSearchParams
=
new
URLSearchParams
(
searchParams
)
newSearchParams
.
delete
(
'toolId'
)
setSearchParams
(
newSearchParams
,
{
replace
:
true
})
}
setSelectedToolId
(
null
)
setIsToolBtnActive
(
true
)
// 存入默认高亮按钮信息到缓存
if
(
toolList
.
length
>
0
)
{
if
(
toolList
.
length
>
0
)
{
const
defaultTool
=
toolList
[
0
]
const
currentTool
=
toolList
.
find
(
tool
=>
String
(
tool
.
toolId
)
===
String
(
currentToolId
))
safeSessionStorageSetItem
(
'currentToolId'
,
defaultTool
.
toolId
)
if
(
currentTool
?.
toolName
)
{
safeSessionStorageSetItem
(
'currentToolName'
,
defaul
tTool
.
toolName
)
safeSessionStorageSetItem
(
'currentToolName'
,
curren
tTool
.
toolName
)
console
.
log
(
'[chat-toolid-log] ChatEditor 逻辑三 setItem:'
,
defaultTool
.
toolId
,
'| line:169'
)
}
}
}
setSessionToolId
(
String
(
currentToolId
))
return
return
}
}
...
@@ -188,11 +188,14 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
...
@@ -188,11 +188,14 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
setSearchParams
(
newSearchParams
,
{
replace
:
true
})
setSearchParams
(
newSearchParams
,
{
replace
:
true
})
setSelectedToolId
(
null
)
setSelectedToolId
(
null
)
setIsToolBtnActive
(
true
)
setIsToolBtnActive
(
true
)
//
存入默认高亮按钮信息到缓存
//
默认高亮第0个工具:直接写入第0个工具的 toolId(与你的期望保持一致)
if
(
toolList
.
length
>
0
)
{
if
(
toolList
.
length
>
0
)
{
const
defaultTool
=
toolList
[
0
]
const
defaultTool
=
toolList
[
0
]
safeSessionStorageSetItem
(
'currentToolId'
,
defaultTool
.
toolId
)
safeSessionStorageSetItem
(
'currentToolId'
,
String
(
defaultTool
.
toolId
)
)
safeSessionStorageSetItem
(
'currentToolName'
,
defaultTool
.
toolName
)
safeSessionStorageSetItem
(
'currentToolName'
,
defaultTool
.
toolName
)
setSessionToolId
(
String
(
defaultTool
.
toolId
))
setSelectedToolId
(
String
(
defaultTool
.
toolId
))
setIsToolBtnActive
(
false
)
}
}
return
return
}
}
...
@@ -236,11 +239,14 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
...
@@ -236,11 +239,14 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
else
{
else
{
setSelectedToolId
(
null
)
setSelectedToolId
(
null
)
setIsToolBtnActive
(
true
)
setIsToolBtnActive
(
true
)
//
存入默认高亮按钮信息到缓存
//
默认高亮第0个工具:直接写入第0个工具的 toolId(与你的期望保持一致)
if
(
toolList
.
length
>
0
)
{
if
(
toolList
.
length
>
0
)
{
const
defaultTool
=
toolList
[
0
]
const
defaultTool
=
toolList
[
0
]
safeSessionStorageSetItem
(
'currentToolId'
,
defaultTool
.
toolId
)
safeSessionStorageSetItem
(
'currentToolId'
,
String
(
defaultTool
.
toolId
)
)
safeSessionStorageSetItem
(
'currentToolName'
,
defaultTool
.
toolName
)
safeSessionStorageSetItem
(
'currentToolName'
,
defaultTool
.
toolName
)
setSessionToolId
(
String
(
defaultTool
.
toolId
))
setSelectedToolId
(
String
(
defaultTool
.
toolId
))
setIsToolBtnActive
(
false
)
}
}
}
}
},
[
currentToolId
,
sessionToolId
,
toolIdFromUrl
,
searchParams
,
setSearchParams
,
fromCollect
,
toolList
])
},
[
currentToolId
,
sessionToolId
,
toolIdFromUrl
,
searchParams
,
setSearchParams
,
fromCollect
,
toolList
])
...
@@ -313,17 +319,9 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
...
@@ -313,17 +319,9 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
return
return
if
(
checkAuth
())
{
if
(
checkAuth
())
{
if
(
content
.
trim
())
{
if
(
content
.
trim
())
{
// 只在提质增效模式下传递 toolId,制度活化不传
// 提交时优先使用当前选中 toolId,其次使用缓存中的 currentToolId
let
toolId
:
string
|
undefined
// 不在点击时/提交时使用第0个默认值兜底,避免覆盖用户真实选择
const
toolId
=
selectedToolId
||
safeSessionStorageGetItem
(
'currentToolId'
)
||
undefined
if
(
selectedToolId
)
{
// 提质增效模式:使用选中的 toolId
toolId
=
selectedToolId
}
else
{
// 制度活化:使用第0个工具的 toolId
toolId
=
toolList
[
0
]?.
toolId
}
onSubmit
?.(
content
.
trim
(),
toolId
)
onSubmit
?.(
content
.
trim
(),
toolId
)
setContent
(
''
)
setContent
(
''
)
if
(
editorRef
.
current
)
{
if
(
editorRef
.
current
)
{
...
@@ -358,26 +356,27 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
...
@@ -358,26 +356,27 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
// 获取默认工具信息
// 获取默认工具信息
const
defaultTool
=
toolList
.
length
>
0
?
toolList
[
0
]
:
{
toolId
:
''
,
toolName
:
'默认工具'
}
const
defaultTool
=
toolList
.
length
>
0
?
toolList
[
0
]
:
{
toolId
:
''
,
toolName
:
'默认工具'
}
// 通知上层开始 loading
// 通知上层开始 loading
onToolClick
?.(
true
,
undefined
,
defaultTool
.
toolName
,
false
,
undefined
,
true
)
onToolClick
?.(
true
,
String
(
defaultTool
.
toolId
||
''
)
,
defaultTool
.
toolName
,
false
,
undefined
,
true
)
try
{
try
{
// 重置提交按钮状态
// 重置提交按钮状态
dispatch
(
setIsAsking
(
false
))
dispatch
(
setIsAsking
(
false
))
// 先更新 Redux,确保状态同步
// 你的期望:默认高亮第0个且写入缓存,因此这里不清空 toolId,而是把第0个当作“已选中”
dispatch
(
clearCurrentToolId
())
const
defaultToolId
=
String
(
defaultTool
.
toolId
||
''
)
dispatch
(
setCurrentToolId
(
defaultToolId
))
// 立即更新本地状态,让 UI 立即响应
// 立即更新本地状态,让 UI 立即响应
setIsToolBtnActive
(
tru
e
)
setIsToolBtnActive
(
fals
e
)
setSelectedToolId
(
null
)
setSelectedToolId
(
defaultToolId
)
safeSessionStorageRemoveItem
(
'showToolQuestion'
)
safeSessionStorageRemoveItem
(
'showToolQuestion'
)
// 存入默认高亮按钮信息到缓存
// 存入默认高亮按钮信息到缓存
if
(
toolList
.
length
>
0
)
{
if
(
toolList
.
length
>
0
)
{
safeSessionStorage
RemoveItem
(
'currentToolId'
)
safeSessionStorage
SetItem
(
'currentToolId'
,
defaultToolId
)
safeSessionStorageSetItem
(
'currentToolName'
,
defaultTool
.
toolName
)
safeSessionStorageSetItem
(
'currentToolName'
,
defaultTool
.
toolName
)
setSessionToolId
(
null
)
setSessionToolId
(
defaultToolId
)
console
.
log
(
'[chat-toolid-log] ChatEditor defaultTool
clearSessionToolId'
,
'| line:364'
)
console
.
log
(
'[chat-toolid-log] ChatEditor defaultTool
setSessionToolId:'
,
defaultToolId
,
'| line:364'
)
}
}
setShowToolQuestion
(
false
)
setShowToolQuestion
(
false
)
// 先通知上层更新欢迎语(即便后续接口异常也能生效)
// 先通知上层更新欢迎语(即便后续接口异常也能生效)
onToolClick
?.(
true
,
undefine
d
,
defaultTool
.
toolName
,
false
)
onToolClick
?.(
true
,
defaultToolI
d
,
defaultTool
.
toolName
,
false
)
// 清空路由中的 toolId 参数
// 清空路由中的 toolId 参数
if
(
toolIdFromUrl
)
{
if
(
toolIdFromUrl
)
{
const
newSearchParams
=
new
URLSearchParams
(
searchParams
)
const
newSearchParams
=
new
URLSearchParams
(
searchParams
)
...
@@ -388,21 +387,18 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
...
@@ -388,21 +387,18 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
// 先调用 fetchSessionConversationId 获取会话ID
// 先调用 fetchSessionConversationId 获取会话ID
// 等待 token 就绪后再调用接口
// 等待 token 就绪后再调用接口
await
waitForToken
()
await
waitForToken
()
const
requestData
=
{
const
res
=
await
fetchSessionConversationId
({})
busiId
:
defaultTool
.
toolId
,
}
const
res
=
await
fetchSessionConversationId
(
requestData
)
if
(
res
?.
data
?.
conversationId
)
{
if
(
res
?.
data
?.
conversationId
)
{
const
conversationId
=
res
.
data
.
conversationId
const
conversationId
=
res
.
data
.
conversationId
// 获取到会话ID后,通知上层更新欢迎语并传递 conversationId
// 获取到会话ID后,通知上层更新欢迎语并传递 conversationId
onToolClick
?.(
true
,
undefine
d
,
defaultTool
.
toolName
,
false
,
conversationId
)
onToolClick
?.(
true
,
defaultToolI
d
,
defaultTool
.
toolName
,
false
,
conversationId
)
// 在 navigate 之前设置标记,避免 Chat 组件的 useEffect 重复调用接口
// 在 navigate 之前设置标记,避免 Chat 组件的 useEffect 重复调用接口
sessionStorage
.
setItem
(
'toolHistoryLoading'
,
conversationId
)
sessionStorage
.
setItem
(
'toolHistoryLoading'
,
conversationId
)
// 更新路由到新的会话ID
// 更新路由到新的会话ID
navigate
(
`/chat/
${
conversationId
}
`
,
{
navigate
(
`/chat/
${
conversationId
}
`
,
{
replace
:
true
,
replace
:
true
,
state
:
{
state
:
{
toolId
:
defaultTool
.
tool
Id
,
toolId
:
defaultToolId
,
skipHistoryLoad
:
true
,
// 标记跳过历史记录加载,因为 ChatEditor 会处理
skipHistoryLoad
:
true
,
// 标记跳过历史记录加载,因为 ChatEditor 会处理
},
},
})
})
...
@@ -414,7 +410,7 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
...
@@ -414,7 +410,7 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
window
.
dispatchEvent
(
new
CustomEvent
(
'toolHistoryLoaded'
,
{
window
.
dispatchEvent
(
new
CustomEvent
(
'toolHistoryLoaded'
,
{
detail
:
{
detail
:
{
conversationId
,
conversationId
,
toolId
:
defaultTool
.
tool
Id
,
toolId
:
defaultToolId
,
toolName
:
defaultTool
.
toolName
,
toolName
:
defaultTool
.
toolName
,
qaRecords
:
qaRes
?.
data
||
[],
qaRecords
:
qaRes
?.
data
||
[],
},
},
...
@@ -430,7 +426,7 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
...
@@ -430,7 +426,7 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
}
}
finally
{
finally
{
// 通知上层结束 loading
// 通知上层结束 loading
onToolClick
?.(
true
,
undefined
,
defaultTool
.
toolName
,
false
,
undefined
,
false
)
onToolClick
?.(
true
,
String
(
defaultTool
.
toolId
||
''
)
,
defaultTool
.
toolName
,
false
,
undefined
,
false
)
}
}
}
}
...
@@ -461,10 +457,7 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
...
@@ -461,10 +457,7 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
// 先调用 fetchSessionConversationId 获取会话ID
// 先调用 fetchSessionConversationId 获取会话ID
// 等待 token 就绪后再调用接口
// 等待 token 就绪后再调用接口
await
waitForToken
()
await
waitForToken
()
const
requestData
=
{
const
res
=
await
fetchSessionConversationId
({})
busiId
:
tool
.
toolId
,
}
const
res
=
await
fetchSessionConversationId
(
requestData
)
if
(
res
?.
data
?.
conversationId
)
{
if
(
res
?.
data
?.
conversationId
)
{
const
conversationId
=
res
.
data
.
conversationId
const
conversationId
=
res
.
data
.
conversationId
// 获取到会话ID后,通知上层更新欢迎语并传递 conversationId
// 获取到会话ID后,通知上层更新欢迎语并传递 conversationId
...
@@ -495,7 +488,7 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
...
@@ -495,7 +488,7 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
}))
}))
// 提质增效模式下,延迟触发自动提问接口
// 提质增效模式下,延迟触发自动提问接口
// 使用双重 requestAnimationFrame 确保 Chat 组件的 currentIdRef 已经更新
// 使用双重 requestAnimationFrame 确保 Chat 组件的 currentIdRef 已经更新
if
(
tool
.
toolId
===
'6712395743241'
)
{
if
(
String
(
tool
.
toolId
)
===
'6712395743241'
)
{
console
.
log
(
'[ChatEditor] 提质增效模式 - 准备延迟触发 autoSubmitQuestion'
,
{
conversationId
,
toolId
:
tool
.
toolId
})
console
.
log
(
'[ChatEditor] 提质增效模式 - 准备延迟触发 autoSubmitQuestion'
,
{
conversationId
,
toolId
:
tool
.
toolId
})
requestAnimationFrame
(()
=>
{
requestAnimationFrame
(()
=>
{
requestAnimationFrame
(()
=>
{
requestAnimationFrame
(()
=>
{
...
@@ -512,6 +505,21 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
...
@@ -512,6 +505,21 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
})
})
})
})
}
}
// 业务洞察模式:点击按钮后先开启主工作流(不展示用户问题)
if
(
String
(
tool
.
toolId
)
===
'6712395743242'
)
{
console
.
log
(
'[ChatEditor] 业务洞察模式 - 准备触发 startBusinessInsight'
,
{
conversationId
,
toolId
:
tool
.
toolId
})
requestAnimationFrame
(()
=>
{
requestAnimationFrame
(()
=>
{
console
.
log
(
'[ChatEditor] 业务洞察模式 - 触发 startBusinessInsight 事件'
,
{
conversationId
,
toolId
:
tool
.
toolId
})
window
.
dispatchEvent
(
new
CustomEvent
(
'startBusinessInsight'
,
{
detail
:
{
conversationId
,
toolId
:
tool
.
toolId
,
},
}))
})
})
}
// 清除标记,避免影响后续路由切换
// 清除标记,避免影响后续路由切换
sessionStorage
.
removeItem
(
'toolHistoryLoading'
)
sessionStorage
.
removeItem
(
'toolHistoryLoading'
)
}
}
...
@@ -660,9 +668,8 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
...
@@ -660,9 +668,8 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
const
toolIdStr
=
String
(
tool
.
toolId
)
const
toolIdStr
=
String
(
tool
.
toolId
)
const
isSelectedByState
=
selectedToolId
&&
toolIdStr
===
String
(
selectedToolId
)
const
isSelectedByState
=
selectedToolId
&&
toolIdStr
===
String
(
selectedToolId
)
const
isSelectedBySession
=
!
selectedToolId
&&
sessionToolId
&&
toolIdStr
===
String
(
sessionToolId
)
const
isSelectedBySession
=
!
selectedToolId
&&
sessionToolId
&&
toolIdStr
===
String
(
sessionToolId
)
// 默认高亮第0个工具:路由内没有 toolId 或 toolId 为空时默认高亮,点击后也要高亮
// 高亮仅根据“真实选择状态”决定:点击后的 selectedToolId 或缓存 sessionToolId
const
isDefaultHighlight
=
index
===
0
&&
isToolBtnActive
&&
!
selectedToolId
&&
!
sessionToolId
&&
!
toolIdFromUrl
const
isSelected
=
Boolean
(
isSelectedByState
||
isSelectedBySession
)
const
isSelected
=
isSelectedByState
||
isSelectedBySession
||
isDefaultHighlight
const
baseBtnClass
const
baseBtnClass
=
'w-auto h-[32px] px-3 rounded-full shadow-none text-[12px] flex items-center gap-2 transition-all duration-200 border'
=
'w-auto h-[32px] px-3 rounded-full shadow-none text-[12px] flex items-center gap-2 transition-all duration-200 border'
...
@@ -673,15 +680,11 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
...
@@ -673,15 +680,11 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
const
selectedColor
=
isSelected
?
'primary'
:
'default'
const
selectedColor
=
isSelected
?
'primary'
:
'default'
const
handleButtonPress
=
async
()
=>
{
const
handleButtonPress
=
async
()
=>
{
// 点击即同步缓存,制度活化清空 toolId,工具模式写入当前 toolId
// 你的期望:默认高亮第0个也要写入缓存,因此无论点击哪个按钮都写入该按钮的 toolId
if
(
index
===
0
)
{
safeSessionStorageRemoveItem
(
'currentToolId'
)
setSessionToolId
(
null
)
}
else
{
safeSessionStorageSetItem
(
'currentToolId'
,
toolIdStr
)
safeSessionStorageSetItem
(
'currentToolId'
,
toolIdStr
)
setSessionToolId
(
toolIdStr
)
setSessionToolId
(
toolIdStr
)
}
setSelectedToolId
(
toolIdStr
)
setIsToolBtnActive
(
false
)
safeSessionStorageSetItem
(
'currentToolName'
,
tool
.
toolName
||
''
)
safeSessionStorageSetItem
(
'currentToolName'
,
tool
.
toolName
||
''
)
// 高亮状态直接返回,避免重复触发后续逻辑
// 高亮状态直接返回,避免重复触发后续逻辑
if
(
isSelected
)
if
(
isSelected
)
...
...
src/hooks/useBusinessInsightWorkflow.ts
0 → 100644
View file @
8c98a5a1
import
{
useCallback
,
useEffect
,
useRef
}
from
'react'
import
type
{
ChatRecord
}
from
'@/types/chat'
type
SubmitQuestion
=
(
question
:
string
,
productCode
?:
string
,
toolId
?:
string
,
extraParams
?:
{
paramMap
?:
Record
<
string
,
string
>
recordId
?:
string
recordType
?:
string
workFlowSessionId
?:
string
isReask
?:
boolean
busiType
?:
string
},
workFlowSessionId
?:
string
,
recordId
?:
string
,
)
=>
void
function
tryParseWorkflowDirective
(
answerText
:
string
):
{
recordType
:
string
,
question
?:
string
}
|
null
{
const
trimmed
=
(
answerText
||
''
).
trim
()
if
(
!
trimmed
)
return
null
if
(
!
(
trimmed
.
startsWith
(
'{'
)
&&
trimmed
.
endsWith
(
'}'
)))
return
null
try
{
const
obj
=
JSON
.
parse
(
trimmed
)
if
(
obj
&&
typeof
obj
===
'object'
&&
typeof
obj
.
recordType
===
'string'
)
{
return
{
recordType
:
obj
.
recordType
,
question
:
typeof
obj
.
question
===
'string'
?
obj
.
question
:
undefined
,
}
}
}
catch
{
// ignore
}
return
null
}
export
function
useBusinessInsightWorkflow
(
params
:
{
enabled
:
boolean
toolId
:
string
conversationIdRef
:
React
.
MutableRefObject
<
string
|
undefined
>
items
:
ChatRecord
[]
onSubmitQuestion
:
SubmitQuestion
})
{
const
{
enabled
,
toolId
,
conversationIdRef
,
items
,
onSubmitQuestion
}
=
params
const
modeRef
=
useRef
<
'main'
|
'sub'
>
(
'main'
)
const
startMain
=
useCallback
(()
=>
{
if
(
!
enabled
)
return
modeRef
.
current
=
'main'
// 开启主工作流:不传 question,避免展示用户气泡
onSubmitQuestion
(
''
,
undefined
,
toolId
,
{
recordType
:
'A12'
,
busiType
:
'01'
})
},
[
enabled
,
onSubmitQuestion
,
toolId
])
// 监听外部事件:点击业务洞察按钮后开启主工作流
useEffect
(()
=>
{
if
(
!
enabled
)
return
const
handler
=
(
event
:
CustomEvent
)
=>
{
const
{
conversationId
,
toolId
:
eventToolId
}
=
(
event
.
detail
||
{})
as
any
if
(
String
(
eventToolId
??
''
)
!==
String
(
toolId
))
return
if
(
conversationId
&&
conversationId
!==
conversationIdRef
.
current
)
return
startMain
()
}
window
.
addEventListener
(
'startBusinessInsight'
,
handler
as
EventListener
)
return
()
=>
window
.
removeEventListener
(
'startBusinessInsight'
,
handler
as
EventListener
)
},
[
enabled
,
startMain
,
toolId
,
conversationIdRef
])
// 最小状态机:主流程 answer=JSON → 开启子流程;子流程 end=true → 回主流程
useEffect
(()
=>
{
if
(
!
enabled
)
return
const
last
=
[...
items
].
reverse
().
find
(
r
=>
r
.
role
===
'ai'
&&
r
.
answerList
?.[
0
])
const
lastAnswer
=
last
?.
answerList
?.[
0
]
if
(
!
lastAnswer
)
return
// 只在本轮流式结束后处理,避免边打字边误触发
if
(
lastAnswer
.
endAnswerFlag
!==
true
)
return
// 子流程结束回主流程(后端约定:answer.end === true)
const
end
=
(
lastAnswer
as
any
)?.
end
===
true
if
(
modeRef
.
current
===
'sub'
&&
end
)
{
modeRef
.
current
=
'main'
const
backQuestion
=
(
lastAnswer
as
any
)?.
question
const
q
=
typeof
backQuestion
===
'string'
?
backQuestion
.
trim
()
:
''
if
(
q
)
{
onSubmitQuestion
(
q
,
undefined
,
toolId
,
{
recordType
:
'A12'
,
busiType
:
'01'
})
}
else
{
onSubmitQuestion
(
''
,
undefined
,
toolId
,
{
recordType
:
'A12'
,
busiType
:
'01'
})
}
return
}
// 主流程收到 JSON 指令:开启子流程
if
(
modeRef
.
current
===
'main'
)
{
const
directive
=
tryParseWorkflowDirective
(
lastAnswer
.
answer
)
if
(
directive
?.
recordType
&&
directive
.
recordType
!==
'A12'
)
{
modeRef
.
current
=
'sub'
// 第三步:开启子工作流(不传 question,避免展示用户气泡)
onSubmitQuestion
(
''
,
undefined
,
toolId
,
{
recordType
:
directive
.
recordType
,
busiType
:
'01'
})
}
}
},
[
enabled
,
items
,
onSubmitQuestion
,
toolId
])
return
{
startMain
,
}
}
src/pages/Chat/Chat.tsx
View file @
8c98a5a1
...
@@ -21,6 +21,7 @@ import { useAppDispatch, useAppSelector } from '@/store/hook'
...
@@ -21,6 +21,7 @@ import { useAppDispatch, useAppSelector } from '@/store/hook'
import
ScrollBtoIcon
from
'@/assets/svg/scrollBto.svg?react'
import
ScrollBtoIcon
from
'@/assets/svg/scrollBto.svg?react'
import
{
setIsAsking
}
from
'@/store/chatSlice'
import
{
setIsAsking
}
from
'@/store/chatSlice'
import
SdreamLoading
from
'@/components/SdreamLoading'
import
SdreamLoading
from
'@/components/SdreamLoading'
import
{
useBusinessInsightWorkflow
}
from
'@/hooks/useBusinessInsightWorkflow'
function
makeLocalGroupId
(
prefix
:
string
)
{
function
makeLocalGroupId
(
prefix
:
string
)
{
try
{
try
{
...
@@ -308,7 +309,7 @@ export const Chat: React.FC = () => {
...
@@ -308,7 +309,7 @@ export const Chat: React.FC = () => {
// 判断是否为提质增效模式的自动调用(空问题)
// 判断是否为提质增效模式的自动调用(空问题)
const
isEmptyQuestion
=
!
question
.
trim
()
const
isEmptyQuestion
=
!
question
.
trim
()
const
isQualityImprovement
=
resolvedToolId
===
'6712395743241'
const
isQualityImprovement
=
resolvedToolId
===
'6712395743241'
const
isBusinessInsight
=
resolvedToolId
===
'6712395743242'
const
isBusinessInsight
=
String
(
resolvedToolId
??
''
)
===
'6712395743242'
console
.
log
(
'工具id3'
,
{
console
.
log
(
'工具id3'
,
{
question
,
question
,
questionLength
:
question
.
length
,
questionLength
:
question
.
length
,
...
@@ -455,6 +456,12 @@ export const Chat: React.FC = () => {
...
@@ -455,6 +456,12 @@ export const Chat: React.FC = () => {
requestBody
.
recordType
=
'01'
requestBody
.
recordType
=
'01'
}
}
// 业务洞察:toolId 为 6712395743242(基础逻辑:默认 recordType=A12,允许 extraParams 覆盖)
if
(
String
(
resolvedToolId
??
''
)
===
'6712395743242'
&&
!
extraParams
?.
recordType
)
{
requestBody
.
busiType
=
'01'
requestBody
.
recordType
=
'A12'
}
fetchStreamResponse
(
fetchStreamResponse
(
fetchUrl
,
fetchUrl
,
requestBody
,
requestBody
,
...
@@ -586,16 +593,37 @@ export const Chat: React.FC = () => {
...
@@ -586,16 +593,37 @@ export const Chat: React.FC = () => {
})
})
}
}
// 业务洞察最小工作流状态机(主↔子切换)
useBusinessInsightWorkflow
({
enabled
:
String
(
safeSessionStorageGetItem
(
'currentToolId'
)
||
currentToolId
||
''
)
===
'6712395743242'
,
toolId
:
'6712395743242'
,
conversationIdRef
:
currentIdRef
,
items
:
allItems
,
onSubmitQuestion
:
handleSubmitQuestion
,
})
/** 处理 workflow 表单提交 */
/** 处理 workflow 表单提交 */
const
handleWorkflowSubmit
=
useCallback
(
async
(
paramMap
:
Record
<
string
,
string
>
,
recordId
?:
string
,
workFlowSessionId
?:
string
)
=>
{
const
handleWorkflowSubmit
=
useCallback
(
async
(
paramMap
:
Record
<
string
,
string
>
,
recordId
?:
string
,
workFlowSessionId
?:
string
)
=>
{
// 优先取最近一次带 cardList 的 AI 回答里的 recordType(业务洞察子工作流会用到)
let
recordType
:
string
|
undefined
for
(
let
i
=
allItems
.
length
-
1
;
i
>=
0
;
i
--
)
{
const
item
=
allItems
[
i
]
const
a
=
item
.
role
===
'ai'
?
item
.
answerList
?.[
0
]
:
undefined
const
hasCards
=
Array
.
isArray
(
a
?.
cardList
)
&&
a
!
.
cardList
.
length
>
0
if
(
a
&&
hasCards
&&
a
.
recordType
)
{
recordType
=
a
.
recordType
break
}
}
// workflow 提交时,question 可以为空字符串,但需要传递 paramMap、recordId 和 workFlowSessionId
// workflow 提交时,question 可以为空字符串,但需要传递 paramMap、recordId 和 workFlowSessionId
await
handleSubmitQuestion
(
''
,
undefined
,
undefined
,
{
await
handleSubmitQuestion
(
''
,
undefined
,
undefined
,
{
paramMap
,
paramMap
,
recordId
,
recordId
,
workFlowSessionId
,
workFlowSessionId
,
recordType
:
'A01'
,
recordType
:
recordType
||
'A01'
,
busiType
:
'01'
,
})
})
},
[])
},
[
allItems
,
handleSubmitQuestion
])
/** 获取qa记录 */
/** 获取qa记录 */
const
getUserQaRecordPage
=
useCallback
(
async
(
conversationId
:
string
,
toolId
?:
string
)
=>
{
const
getUserQaRecordPage
=
useCallback
(
async
(
conversationId
:
string
,
toolId
?:
string
)
=>
{
...
@@ -1110,14 +1138,19 @@ export const Chat: React.FC = () => {
...
@@ -1110,14 +1138,19 @@ export const Chat: React.FC = () => {
// 如果历史记录中 firstQaFlag 为 true,隐藏 UI 但保留组件渲染(确保自动提交逻辑能执行)
// 如果历史记录中 firstQaFlag 为 true,隐藏 UI 但保留组件渲染(确保自动提交逻辑能执行)
const
shouldHideHistoryItem
=
record
.
role
===
'ai'
&&
record
.
answerList
?.[
0
]?.
firstQaFlag
===
true
const
shouldHideHistoryItem
=
record
.
role
===
'ai'
&&
record
.
answerList
?.[
0
]?.
firstQaFlag
===
true
// 如果是自动调用提问接口(空问题且是流式返回的新记录),不显示问题和回答
// 判断条件:question === undefined(空问题)且 isShow === false(流式返回的新记录,不是历史记录)
const
shouldHideEmptyQuestionAnswer
=
record
.
role
===
'ai'
&&
record
.
question
===
undefined
&&
record
.
answerList
?.[
0
]?.
isShow
===
false
// 白名单:当同一条 AI 记录里同时有 question + answer(且 firstQaFlag 不为 true)时,强制展示,避免误隐藏
const
hasQuestion
=
typeof
record
.
question
===
'string'
&&
record
.
question
.
trim
().
length
>
0
const
firstAnswer
=
record
.
answerList
?.[
0
]
const
firstAnswer
=
record
.
answerList
?.[
0
]
const
hasAnswer
=
typeof
firstAnswer
?.
answer
===
'string'
&&
firstAnswer
.
answer
.
trim
().
length
>
0
const
hasAnswer
=
typeof
firstAnswer
?.
answer
===
'string'
&&
firstAnswer
.
answer
.
trim
().
length
>
0
const
hasCardList
=
Array
.
isArray
(
firstAnswer
?.
cardList
)
&&
firstAnswer
!
.
cardList
.
length
>
0
const
hasCardList
=
Array
.
isArray
(
firstAnswer
?.
cardList
)
&&
firstAnswer
!
.
cardList
.
length
>
0
// 自动调用提问接口(空 question)时:
// - 第一步/第三步“开启工作流”不应展示在页面内(通常没有 answer,也没有 cardList)
// - 但第三步可能返回 cardList(需要展示表单),因此仅在“既无 answer 也无 cardList”时才隐藏
const
shouldHideEmptyQuestionAnswer
=
record
.
role
===
'ai'
&&
record
.
question
===
undefined
&&
firstAnswer
?.
isShow
===
false
&&
!
hasAnswer
&&
!
hasCardList
// 白名单:当同一条 AI 记录里同时有 question + answer(且 firstQaFlag 不为 true)时,强制展示,避免误隐藏
const
hasQuestion
=
typeof
record
.
question
===
'string'
&&
record
.
question
.
trim
().
length
>
0
const
shouldForceShow
=
record
.
role
===
'ai'
const
shouldForceShow
=
record
.
role
===
'ai'
&&
hasQuestion
&&
hasQuestion
&&
(
hasAnswer
||
hasCardList
)
&&
(
hasAnswer
||
hasCardList
)
...
...
src/pages/Chat/components/ChatItem/ChatAnswerRecommend.tsx
View file @
8c98a5a1
...
@@ -79,6 +79,7 @@ export const ChatAnswerRecommend: React.FC<ChatAnswerRecommendProps> = ({ answer
...
@@ -79,6 +79,7 @@ export const ChatAnswerRecommend: React.FC<ChatAnswerRecommendProps> = ({ answer
recordType
,
recordType
,
)
)
if
(
res
.
ok
)
{
if
(
res
.
ok
)
{
console
.
log
(
'推荐问题列表'
,
res
.
data
.
questionList
)
setQuestionList
(
res
.
data
.
questionList
)
setQuestionList
(
res
.
data
.
questionList
)
}
}
}
}
...
...
src/pages/Home/HomeNew.tsx
View file @
8c98a5a1
...
@@ -7,14 +7,14 @@ import styles from './Home.module.less'
...
@@ -7,14 +7,14 @@ import styles from './Home.module.less'
import
{
QuestionList
}
from
'./components/QuestionList'
import
{
QuestionList
}
from
'./components/QuestionList'
import
HomeIcon2
from
'@/assets/homeIcon2.png'
import
HomeIcon2
from
'@/assets/homeIcon2.png'
import
SmartIce
from
'@/assets/smart-ice.png'
import
SmartIce
from
'@/assets/smart-ice.png'
import
{
clearCurrentToolId
,
fetchConversations
,
setCurrentConversation
,
setCurrentToolId
,
setNavigationFlag
}
from
'@/store/conversationSlice'
import
{
fetchConversations
,
setCurrentConversation
,
setCurrentToolId
,
setNavigationFlag
}
from
'@/store/conversationSlice'
import
{
useAppDispatch
,
useAppSelector
}
from
'@/store/hook'
import
{
useAppDispatch
,
useAppSelector
}
from
'@/store/hook'
import
{
fetchEfficiencyQuestionList
}
from
'@/api/home'
import
{
fetchEfficiencyQuestionList
}
from
'@/api/home'
import
SdreamLoading
from
'@/components/SdreamLoading'
import
SdreamLoading
from
'@/components/SdreamLoading'
import
{
fetchLoginByToken
,
fetchLoginByUid
}
from
'@/api/common'
import
{
fetchLoginByToken
,
fetchLoginByUid
}
from
'@/api/common'
import
{
fetchSessionConversationId
}
from
'@/api/conversation'
import
{
fetchSessionConversationId
}
from
'@/api/conversation'
import
{
fetchCheckTokenApi
}
from
'@/api/chat'
import
{
fetchCheckTokenApi
}
from
'@/api/chat'
import
{
getUserRolesFromRoute
,
safeLocalStorageGetItem
,
safeLocalStorageSetItem
,
safeSessionStorageGetItem
,
safeSessionStorage
RemoveItem
,
safeSessionStorage
SetItem
,
waitForToken
}
from
'@/lib/utils'
import
{
getUserRolesFromRoute
,
safeLocalStorageGetItem
,
safeLocalStorageSetItem
,
safeSessionStorageGetItem
,
safeSessionStorageSetItem
,
waitForToken
}
from
'@/lib/utils'
// 从 localStorage 获取 token 的辅助函数
// 从 localStorage 获取 token 的辅助函数
function
getTokenFromStorage
():
string
|
null
{
function
getTokenFromStorage
():
string
|
null
{
...
@@ -70,14 +70,13 @@ export const Home: React.FC = () => {
...
@@ -70,14 +70,13 @@ export const Home: React.FC = () => {
const
currentConversationId
=
useAppSelector
(
state
=>
state
.
conversation
.
currentConversationId
)
const
currentConversationId
=
useAppSelector
(
state
=>
state
.
conversation
.
currentConversationId
)
const
hasFetched
=
useRef
(
false
)
const
hasFetched
=
useRef
(
false
)
const
hasCalledBusinessApis
=
useRef
(
false
)
// 防止业务接口重复调用
const
hasCalledBusinessApis
=
useRef
(
false
)
// 防止业务接口重复调用
const
initialToolIdRef
=
useRef
<
string
>
(
''
)
// 首次进入时缓存的 toolId,避免登录清理后首次请求丢失
const
prevPathRef
=
useRef
<
string
>
(
location
.
pathname
)
// 记录上一次路径,用于检测从收藏页面返回
const
prevPathRef
=
useRef
<
string
>
(
location
.
pathname
)
// 记录上一次路径,用于检测从收藏页面返回
// 使用 useState
// 使用 useState
const
[
otherQuestions
,
setOtherQuestions
]
=
useState
<
any
>
({
content
:
[]
})
const
[
otherQuestions
,
setOtherQuestions
]
=
useState
<
any
>
({
content
:
[]
})
const
[
isToolBtnActive
,
setIsToolBtnActive
]
=
useState
<
boolean
>
(
false
)
const
[
isToolBtnActive
,
setIsToolBtnActive
]
=
useState
<
boolean
>
(
false
)
const
[
shouldChangeStyle
,
setShouldChangeStyle
]
=
useState
<
boolean
>
(
true
)
const
[
shouldChangeStyle
,
setShouldChangeStyle
]
=
useState
<
boolean
>
(
true
)
// 保存原始的configType为07的数据
// 保存原始的configType为07的数据
const
[
originalOtherQuestions
,
_setOriginalOtherQuestions
]
=
useState
<
any
>
({
content
:
[]
})
const
[
_
originalOtherQuestions
,
_setOriginalOtherQuestions
]
=
useState
<
any
>
({
content
:
[]
})
const
[
token
,
setToken
]
=
useLocalStorageState
<
string
|
undefined
>
(
'__TOKEN__'
,
{
const
[
token
,
setToken
]
=
useLocalStorageState
<
string
|
undefined
>
(
'__TOKEN__'
,
{
defaultValue
:
''
,
defaultValue
:
''
,
...
@@ -149,7 +148,7 @@ export const Home: React.FC = () => {
...
@@ -149,7 +148,7 @@ export const Home: React.FC = () => {
}
}
// 从 sessionStorage 获取 toolId 并确定 recordType
// 从 sessionStorage 获取 toolId 并确定 recordType
const
toolId
=
safeSessionStorageGetItem
(
'currentToolId'
)
||
initialToolIdRef
.
current
||
''
const
toolId
=
safeSessionStorageGetItem
(
'currentToolId'
)
||
''
const
recordType
=
getRecordTypeByToolId
(
toolId
)
const
recordType
=
getRecordTypeByToolId
(
toolId
)
const
res
=
await
fetchEfficiencyQuestionList
({
const
res
=
await
fetchEfficiencyQuestionList
({
...
@@ -158,6 +157,7 @@ export const Home: React.FC = () => {
...
@@ -158,6 +157,7 @@ export const Home: React.FC = () => {
recordType
,
recordType
,
})
})
if
(
res
&&
res
.
data
&&
res
.
data
.
questionList
)
{
if
(
res
&&
res
.
data
&&
res
.
data
.
questionList
)
{
console
.
log
(
'推荐问题列表homeNew'
,
res
.
data
.
questionList
)
setOtherQuestions
((
prev
:
any
)
=>
({
setOtherQuestions
((
prev
:
any
)
=>
({
...
prev
,
...
prev
,
content
:
res
.
data
.
questionList
||
[],
content
:
res
.
data
.
questionList
||
[],
...
@@ -182,25 +182,6 @@ export const Home: React.FC = () => {
...
@@ -182,25 +182,6 @@ export const Home: React.FC = () => {
}))
}))
setIsDataLoaded
(
false
)
// 重置加载状态
setIsDataLoaded
(
false
)
// 重置加载状态
try
{
try
{
const
storedToolId
=
safeSessionStorageGetItem
(
'currentToolId'
)
||
''
// 首页初始化加载常见问题时,允许忽略路由中的 toolId,避免带入上一次的工具 ID
const
shouldForceClearToolId
=
!
storedToolId
let
finalToolId
=
toolId
||
''
// 场景:首页首次挂载(ignoreUrlToolId === true)且为制度活化(!isToolBtn && !toolId)
// 此时无论 sessionStorage 中是否残留上一次的 toolId,都强制使用空字符串,避免带入历史工具 ID
if
(
ignoreUrlToolId
&&
!
isToolBtn
&&
!
toolId
)
{
finalToolId
=
''
}
else
if
(
shouldForceClearToolId
&&
!
isToolBtn
)
{
finalToolId
=
''
}
else
if
(
!
finalToolId
&&
!
isToolBtn
)
{
// 仅在工具模式下才使用回退逻辑,避免制度活化误用上一次的 toolId
finalToolId
=
storedToolId
}
// 优先使用传入的 conversationId,其次从 Redux 获取,最后从路由中获取
// 优先使用传入的 conversationId,其次从 Redux 获取,最后从路由中获取
const
conversationId
=
conversationIdParam
||
currentConversationId
||
(
location
.
pathname
.
startsWith
(
'/chat/'
)
const
conversationId
=
conversationIdParam
||
currentConversationId
||
(
location
.
pathname
.
startsWith
(
'/chat/'
)
?
location
.
pathname
.
split
(
'/'
)[
2
]
?
location
.
pathname
.
split
(
'/'
)[
2
]
...
@@ -211,8 +192,8 @@ export const Home: React.FC = () => {
...
@@ -211,8 +192,8 @@ export const Home: React.FC = () => {
return
return
}
}
//
从 sessionStorage 获取 toolId 并确
定 recordType
//
常见问题只根据缓存 currentToolId 决
定 recordType
const
currentToolId
=
safeSessionStorageGetItem
(
'currentToolId'
)
||
finalToolId
||
initialToolIdRef
.
current
||
''
const
currentToolId
=
safeSessionStorageGetItem
(
'currentToolId'
)
||
''
const
recordType
=
getRecordTypeByToolId
(
currentToolId
)
const
recordType
=
getRecordTypeByToolId
(
currentToolId
)
// 调用真实 API 获取常见问题列表
// 调用真实 API 获取常见问题列表
...
@@ -234,7 +215,7 @@ export const Home: React.FC = () => {
...
@@ -234,7 +215,7 @@ export const Home: React.FC = () => {
finally
{
finally
{
setIsDataLoaded
(
true
)
// 无论成功失败都标记为已加载
setIsDataLoaded
(
true
)
// 无论成功失败都标记为已加载
}
}
},
[
originalOtherQuestions
,
location
.
search
,
location
.
pathname
,
currentConversationId
])
},
[
location
.
search
,
location
.
pathname
,
currentConversationId
])
// 监听工具按钮点击事件
// 监听工具按钮点击事件
useEffect
(()
=>
{
useEffect
(()
=>
{
...
@@ -244,18 +225,16 @@ export const Home: React.FC = () => {
...
@@ -244,18 +225,16 @@ export const Home: React.FC = () => {
// 更新样式控制状态
// 更新样式控制状态
setShouldChangeStyle
(
true
)
setShouldChangeStyle
(
true
)
// 保存当前选择的 toolId 到 Redux
// 统一规则:只要事件里带了 toolId(包括第0个默认按钮),就写入并同步 Redux
if
(
!
isToolBtn
&&
toolId
)
{
if
(
toolId
)
{
// 提质增效模式,保存 toolId
dispatch
(
setCurrentToolId
(
toolId
))
dispatch
(
setCurrentToolId
(
toolId
))
safeSessionStorageSetItem
(
'currentToolId'
,
toolId
)
safeSessionStorageSetItem
(
'currentToolId'
,
toolId
)
console
.
log
(
'[chat-toolid-log] HomeNew setItem:'
,
toolId
,
'| line:253'
)
console
.
log
(
'[chat-toolid-log] HomeNew setItem:'
,
toolId
,
'| line:253'
)
}
}
else
{
else
{
// 制度活化,清除 toolId
// 点击事件没有 toolId 时不覆盖缓存,避免“先清空再被默认第0个回填”
dispatch
(
clearCurrentToolId
())
console
.
log
(
'[chat-toolid-log] HomeNew ignore empty toolId event'
,
'| line:260'
)
sessionStorage
.
removeItem
(
'currentToolId'
)
return
console
.
log
(
'[chat-toolid-log] HomeNew removeItem'
,
'| line:260'
)
}
}
// 如果事件传递了 conversationId,延迟调用以确保路由更新完成
// 如果事件传递了 conversationId,延迟调用以确保路由更新完成
...
@@ -303,23 +282,13 @@ export const Home: React.FC = () => {
...
@@ -303,23 +282,13 @@ export const Home: React.FC = () => {
const
searchParams
=
new
URLSearchParams
(
url
.
search
)
const
searchParams
=
new
URLSearchParams
(
url
.
search
)
const
from
=
searchParams
.
get
(
'from'
)
const
from
=
searchParams
.
get
(
'from'
)
const
_loginCode
=
searchParams
.
get
(
'loginCode'
)
const
_loginCode
=
searchParams
.
get
(
'loginCode'
)
// 记录首次进入时的 toolId,避免在登录流程清理后丢失首次会话参数
if
(
!
initialToolIdRef
.
current
)
{
initialToolIdRef
.
current
=
safeSessionStorageGetItem
(
'currentToolId'
)
||
''
}
// 如果有 loginCode,执行 SSO 登录(包括 from=tactics 的情况)
// 如果有 loginCode,执行 SSO 登录(包括 from=tactics 的情况)
if
(
_loginCode
&&
viteOutputObj
===
'inner'
)
{
if
(
_loginCode
&&
viteOutputObj
===
'inner'
)
{
// 立即设置标志,防止重复执行(仅组件级别,每次组件挂载时会重置)
// 立即设置标志,防止重复执行(仅组件级别,每次组件挂载时会重置)
hasFetched
.
current
=
true
hasFetched
.
current
=
true
// 每次进入页面调用 sso_login 时,先清空 sessionStorage 中的 currentToolId
// 避免关闭标签页后再次打开时使用上次的历史 toolId
safeSessionStorageRemoveItem
(
'currentToolId'
)
try
{
try
{
const
res
=
await
fetchLoginByToken
(
_loginCode
)
const
res
=
await
fetchLoginByToken
(
_loginCode
)
if
(
res
.
data
)
{
if
(
res
.
data
)
{
// 登录成功后先清理旧状态,避免沿用上一次的工具模式
dispatch
(
clearCurrentToolId
())
safeSessionStorageRemoveItem
(
'currentToolId'
)
const
currentUrl
=
new
URL
(
window
.
location
.
href
)
const
currentUrl
=
new
URL
(
window
.
location
.
href
)
if
(
currentUrl
.
searchParams
.
has
(
'toolId'
))
{
if
(
currentUrl
.
searchParams
.
has
(
'toolId'
))
{
currentUrl
.
searchParams
.
delete
(
'toolId'
)
currentUrl
.
searchParams
.
delete
(
'toolId'
)
...
@@ -383,8 +352,6 @@ export const Home: React.FC = () => {
...
@@ -383,8 +352,6 @@ export const Home: React.FC = () => {
const
actualToken
=
getTokenFromStorage
()
||
res
.
data
.
token
const
actualToken
=
getTokenFromStorage
()
||
res
.
data
.
token
if
(
actualToken
&&
!
hasCalledBusinessApis
.
current
)
{
if
(
actualToken
&&
!
hasCalledBusinessApis
.
current
)
{
hasCalledBusinessApis
.
current
=
true
hasCalledBusinessApis
.
current
=
true
// 触发自定义事件,通知 ChatEditor 强制重置为制度活化
window
.
dispatchEvent
(
new
CustomEvent
(
'forceResetToGeneralMode'
))
const
conversationId
=
await
getSessionConversationId
()
const
conversationId
=
await
getSessionConversationId
()
dispatch
(
fetchConversations
())
dispatch
(
fetchConversations
())
// 2. 拉取常见问题等业务数据
// 2. 拉取常见问题等业务数据
...
@@ -433,9 +400,6 @@ export const Home: React.FC = () => {
...
@@ -433,9 +400,6 @@ export const Home: React.FC = () => {
try
{
try
{
const
res
=
await
fetchLoginByUid
(
'123123'
)
const
res
=
await
fetchLoginByUid
(
'123123'
)
if
(
res
.
data
)
{
if
(
res
.
data
)
{
// 登录成功后先清理旧状态,避免沿用上一次的工具模式
dispatch
(
clearCurrentToolId
())
safeSessionStorageRemoveItem
(
'currentToolId'
)
const
currentUrl
=
new
URL
(
window
.
location
.
href
)
const
currentUrl
=
new
URL
(
window
.
location
.
href
)
if
(
currentUrl
.
searchParams
.
has
(
'toolId'
))
{
if
(
currentUrl
.
searchParams
.
has
(
'toolId'
))
{
currentUrl
.
searchParams
.
delete
(
'toolId'
)
currentUrl
.
searchParams
.
delete
(
'toolId'
)
...
@@ -496,8 +460,6 @@ export const Home: React.FC = () => {
...
@@ -496,8 +460,6 @@ export const Home: React.FC = () => {
const
actualToken
=
getTokenFromStorage
()
||
res
.
data
.
token
const
actualToken
=
getTokenFromStorage
()
||
res
.
data
.
token
if
(
actualToken
&&
!
hasCalledBusinessApis
.
current
)
{
if
(
actualToken
&&
!
hasCalledBusinessApis
.
current
)
{
hasCalledBusinessApis
.
current
=
true
hasCalledBusinessApis
.
current
=
true
// 触发自定义事件,通知 ChatEditor 强制重置为制度活化
window
.
dispatchEvent
(
new
CustomEvent
(
'forceResetToGeneralMode'
))
const
conversationId
=
await
getSessionConversationId
()
const
conversationId
=
await
getSessionConversationId
()
dispatch
(
fetchConversations
())
dispatch
(
fetchConversations
())
// 2. 拉取常见问题等业务数据
// 2. 拉取常见问题等业务数据
...
@@ -523,13 +485,6 @@ export const Home: React.FC = () => {
...
@@ -523,13 +485,6 @@ export const Home: React.FC = () => {
login
()
login
()
},
[])
// 依赖数组为空,只在组件挂载时执行一次
},
[])
// 依赖数组为空,只在组件挂载时执行一次
useEffect
(()
=>
{
// 只有登录成功(拿到 token)后才拉业务接口
if
(
!
token
)
return
dispatch
(
clearCurrentToolId
())
},
[
token
,
dispatch
])
// 监听路径变化,检测从收藏页面返回时刷新问题列表
// 监听路径变化,检测从收藏页面返回时刷新问题列表
useEffect
(()
=>
{
useEffect
(()
=>
{
const
currentPath
=
location
.
pathname
const
currentPath
=
location
.
pathname
...
...
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