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
eb862599
Commit
eb862599
authored
Jan 23, 2026
by
weiyudumei
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 实现 workFlowSessionId 的传递逻辑,从会话历史中查找最后一个有 workFlowSessionId 的答案并传递,重新分析时不传递
parent
974b0191
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
145 additions
and
61 deletions
+145
-61
src/pages/Chat/Chat.tsx
+33
-3
src/pages/Chat/components/ChatItem/ChatAnswerAttchment.tsx
+18
-15
src/pages/Chat/components/ChatItem/ChatAnswerBox.tsx
+38
-6
src/pages/Chat/components/ChatItem/ChatAnswerParser.tsx
+18
-25
src/pages/Chat/components/ChatItem/ChatAnswerShower.tsx
+4
-9
src/pages/ChatTactics/TacticsChat.tsx
+34
-3
No files found.
src/pages/Chat/Chat.tsx
View file @
eb862599
...
@@ -206,7 +206,9 @@ export const Chat: React.FC = () => {
...
@@ -206,7 +206,9 @@ export const Chat: React.FC = () => {
question
:
string
,
question
:
string
,
productCode
?:
string
,
productCode
?:
string
,
toolId
?:
string
,
toolId
?:
string
,
extraParams
?:
{
paramMap
?:
Record
<
string
,
string
>
,
recordId
?:
string
,
recordType
?:
string
,
workFlowSessionId
?:
string
},
extraParams
?:
{
paramMap
?:
Record
<
string
,
string
>
,
recordId
?:
string
,
recordType
?:
string
,
workFlowSessionId
?:
string
,
isReask
?:
boolean
},
workFlowSessionId
?:
string
,
recordId
?:
string
,
)
=>
{
)
=>
{
// 优先读取缓存中的 toolId,再回退到传参或 Redux
// 优先读取缓存中的 toolId,再回退到传参或 Redux
const
sessionToolId
=
sessionStorage
.
getItem
(
'currentToolId'
)
??
undefined
const
sessionToolId
=
sessionStorage
.
getItem
(
'currentToolId'
)
??
undefined
...
@@ -265,11 +267,38 @@ export const Chat: React.FC = () => {
...
@@ -265,11 +267,38 @@ export const Chat: React.FC = () => {
if
(
extraParams
?.
paramMap
)
{
if
(
extraParams
?.
paramMap
)
{
requestBody
.
paramMap
=
extraParams
.
paramMap
requestBody
.
paramMap
=
extraParams
.
paramMap
}
}
// 优先使用 extraParams 中的值,其次使用直接传递的参数
if
(
extraParams
?.
recordId
)
{
if
(
extraParams
?.
recordId
)
{
requestBody
.
recordId
=
extraParams
.
recordId
requestBody
.
recordId
=
extraParams
.
recordId
}
}
if
(
extraParams
?.
workFlowSessionId
)
{
else
if
(
recordId
)
{
requestBody
.
workFlowSessionId
=
extraParams
.
workFlowSessionId
requestBody
.
recordId
=
recordId
}
// workFlowSessionId 的传递逻辑:
// 1. 如果是重新问答(isReask === true),不传递 workFlowSessionId
// 2. 优先使用 extraParams 中的值
// 3. 其次使用直接传递的参数
// 4. 如果都没有,从会话历史中找到最后一个有 workFlowSessionId 的答案
const
isReask
=
extraParams
?.
isReask
===
true
if
(
!
isReask
)
{
if
(
extraParams
?.
workFlowSessionId
)
{
requestBody
.
workFlowSessionId
=
extraParams
.
workFlowSessionId
}
else
if
(
workFlowSessionId
)
{
requestBody
.
workFlowSessionId
=
workFlowSessionId
}
else
{
// 从会话历史中找到最后一个有 workFlowSessionId 的答案
// 注意:这里使用 allItems 的当前值(在添加新记录之前),所以需要从倒数第二个开始查找
for
(
let
i
=
allItems
.
length
-
1
;
i
>=
0
;
i
--
)
{
const
item
=
allItems
[
i
]
if
(
item
.
role
===
'ai'
&&
item
.
answerList
?.[
0
]?.
workFlowSessionId
)
{
requestBody
.
workFlowSessionId
=
item
.
answerList
[
0
].
workFlowSessionId
break
}
}
}
}
}
// 如果传入了 recordType,优先使用传入的值(workflow 提交场景)
// 如果传入了 recordType,优先使用传入的值(workflow 提交场景)
...
@@ -940,6 +969,7 @@ export const Chat: React.FC = () => {
...
@@ -940,6 +969,7 @@ export const Chat: React.FC = () => {
index=
{
index
}
index=
{
index
}
onWorkflowSubmit=
{
handleWorkflowSubmit
}
onWorkflowSubmit=
{
handleWorkflowSubmit
}
isWorkflowSubmitting=
{
isAsking
}
isWorkflowSubmitting=
{
isAsking
}
allItems=
{
allItems
}
/>
/>
)
}
)
}
</
div
>
</
div
>
...
...
src/pages/Chat/components/ChatItem/ChatAnswerAttchment.tsx
View file @
eb862599
...
@@ -16,7 +16,7 @@ import { FilePreviewModal } from '@/components/FilePreviewModal'
...
@@ -16,7 +16,7 @@ import { FilePreviewModal } from '@/components/FilePreviewModal'
interface
ChatAnswerAttachmentProps
{
interface
ChatAnswerAttachmentProps
{
answer
:
Answer
answer
:
Answer
isLastAnswer
?:
boolean
isLastAnswer
?:
boolean
onSubmitQuestion
?:
(
question
:
string
,
productCode
?:
string
)
=>
void
onSubmitQuestion
?:
(
question
:
string
,
productCode
?:
string
,
workFlowSessionId
?:
string
,
recordId
?:
string
)
=>
void
onWorkflowSubmit
?:
(
paramMap
:
Record
<
string
,
string
>
,
recordId
?:
string
,
workFlowSessionId
?:
string
)
=>
void
onWorkflowSubmit
?:
(
paramMap
:
Record
<
string
,
string
>
,
recordId
?:
string
,
workFlowSessionId
?:
string
)
=>
void
isWorkflowSubmitting
?:
boolean
isWorkflowSubmitting
?:
boolean
isAsking
?:
boolean
isAsking
?:
boolean
...
@@ -36,6 +36,9 @@ export const ChatAnswerAttachment: React.FC<ChatAnswerAttachmentProps> = ({
...
@@ -36,6 +36,9 @@ export const ChatAnswerAttachment: React.FC<ChatAnswerAttachmentProps> = ({
const
handleClickBoxItem
=
(
produceName
:
string
,
productCode
:
string
)
=>
{
const
handleClickBoxItem
=
(
produceName
:
string
,
productCode
:
string
)
=>
{
if
(
onSubmitQuestion
)
{
if
(
onSubmitQuestion
)
{
// 注意:workFlowSessionId 和 recordId 应该从会话历史中获取,而不是从当前的 answer
// 这里先传递 undefined,让上层的 handleSubmitQuestionWithWorkflow 来处理
// 因为 ChatAnswerAttachment 无法访问整个会话历史
onSubmitQuestion
(
produceName
,
productCode
)
onSubmitQuestion
(
produceName
,
productCode
)
}
}
}
}
...
@@ -59,7 +62,7 @@ export const ChatAnswerAttachment: React.FC<ChatAnswerAttachmentProps> = ({
...
@@ -59,7 +62,7 @@ export const ChatAnswerAttachment: React.FC<ChatAnswerAttachmentProps> = ({
setDocUrl
(
fileBlobUrl
)
// 传递 blob URL
setDocUrl
(
fileBlobUrl
)
// 传递 blob URL
setPreviewModalOpen
(
true
)
setPreviewModalOpen
(
true
)
}
}
catch
(
error
)
{
catch
(
error
)
{
console
.
error
(
'获取文档链接失败:'
,
error
)
console
.
error
(
'获取文档链接失败:'
,
error
)
}
}
}
}
...
@@ -102,7 +105,7 @@ export const ChatAnswerAttachment: React.FC<ChatAnswerAttachmentProps> = ({
...
@@ -102,7 +105,7 @@ export const ChatAnswerAttachment: React.FC<ChatAnswerAttachmentProps> = ({
<>
<>
<
div
className=
"cardList flex flex-col gap-[20px]"
>
<
div
className=
"cardList flex flex-col gap-[20px]"
>
{
answer
.
cardList
{
answer
.
cardList
&&
answer
.
cardList
.
map
((
attachment
,
index
)
=>
{
&&
answer
.
cardList
.
map
((
attachment
,
index
)
=>
{
if
(
attachment
?.
type
)
{
if
(
attachment
?.
type
)
{
// 使用唯一标识符而不是索引作为 key
// 使用唯一标识符而不是索引作为 key
const
key
=
`${attachment.type}_${attachment.id || index}`
const
key
=
`${attachment.type}_${attachment.id || index}`
...
@@ -120,8 +123,8 @@ export const ChatAnswerAttachment: React.FC<ChatAnswerAttachmentProps> = ({
...
@@ -120,8 +123,8 @@ export const ChatAnswerAttachment: React.FC<ChatAnswerAttachmentProps> = ({
)
}
)
}
{
/* 附件:引用文件 */
}
{
/* 附件:引用文件 */
}
{
attachment
.
type
===
'reference'
{
attachment
.
type
===
'reference'
&&
attachment
.
content
?.
docList
&&
attachment
.
content
?.
docList
&&
attachment
.
content
.
docList
.
length
!==
0
&&
(
&&
attachment
.
content
.
docList
.
length
!==
0
&&
(
<
div
>
<
div
>
<
p
className=
"text-[14px] text-[#8D9795] mb-[12px]"
>
<
p
className=
"text-[14px] text-[#8D9795] mb-[12px]"
>
已为您找到
已为您找到
...
@@ -170,16 +173,16 @@ export const ChatAnswerAttachment: React.FC<ChatAnswerAttachmentProps> = ({
...
@@ -170,16 +173,16 @@ export const ChatAnswerAttachment: React.FC<ChatAnswerAttachmentProps> = ({
)
}
)
}
{
/* 工作流卡片:card-workflow */
}
{
/* 工作流卡片:card-workflow */
}
{
attachment
.
type
===
'card-workflow'
{
attachment
.
type
===
'card-workflow'
&&
attachment
.
content
?.
name
===
'form_input'
&&
attachment
.
content
?.
name
===
'form_input'
&&
attachment
.
content
?.
fieldList
?.
some
(
field
=>
field
.
type
===
'text'
)
&&
(
&&
attachment
.
content
?.
fieldList
?.
some
(
field
=>
field
.
type
===
'text'
)
&&
(
<
CardWorkflowForm
<
CardWorkflowForm
attachment=
{
attachment
}
attachment=
{
attachment
}
answer=
{
answer
}
answer=
{
answer
}
onSubmitWorkflow=
{
onWorkflowSubmit
||
(()
=>
{
})
}
onSubmitWorkflow=
{
onWorkflowSubmit
||
(()
=>
{
})
}
isSubmitting=
{
isWorkflowSubmitting
}
isSubmitting=
{
isWorkflowSubmitting
}
isCompleted=
{
false
}
isCompleted=
{
false
}
/>
/>
)
}
)
}
{
/* 其他 card-* 类型 */
}
{
/* 其他 card-* 类型 */
}
{
attachment
.
type
?.
includes
(
'card-'
)
&&
attachment
.
type
!==
'card-workflow'
&&
(
{
attachment
.
type
?.
includes
(
'card-'
)
&&
attachment
.
type
!==
'card-workflow'
&&
(
<
div
onClick=
{
()
=>
handleClickCard
(
attachment
)
}
>
<
div
onClick=
{
()
=>
handleClickCard
(
attachment
)
}
>
...
...
src/pages/Chat/components/ChatItem/ChatAnswerBox.tsx
View file @
eb862599
...
@@ -17,13 +17,14 @@ interface ChatAnswerBoxProps {
...
@@ -17,13 +17,14 @@ interface ChatAnswerBoxProps {
showIndex
:
number
showIndex
:
number
isLastAnswer
:
boolean
isLastAnswer
:
boolean
index
:
number
index
:
number
onSubmitQuestion
:
(
question
:
string
,
productCode
?:
string
)
=>
void
onSubmitQuestion
:
(
question
:
string
,
productCode
?:
string
,
workFlowSessionId
?:
string
,
recordId
?:
string
)
=>
void
onRecommendLoadingChange
?:
(
loading
:
boolean
)
=>
void
onRecommendLoadingChange
?:
(
loading
:
boolean
)
=>
void
onWorkflowSubmit
?:
(
paramMap
:
Record
<
string
,
string
>
,
recordId
?:
string
)
=>
void
onWorkflowSubmit
?:
(
paramMap
:
Record
<
string
,
string
>
,
recordId
?:
string
)
=>
void
isWorkflowSubmitting
?:
boolean
isWorkflowSubmitting
?:
boolean
allItems
?:
ChatRecord
[]
// 传入整个会话历史,用于查找最后一个 workFlowSessionId
}
}
export
const
ChatAnswerBox
:
React
.
FC
<
ChatAnswerBoxProps
>
=
({
record
,
showIndex
,
isLastAnswer
,
onSubmitQuestion
,
onRecommendLoadingChange
,
onWorkflowSubmit
,
isWorkflowSubmitting
})
=>
{
export
const
ChatAnswerBox
:
React
.
FC
<
ChatAnswerBoxProps
>
=
({
record
,
showIndex
,
isLastAnswer
,
onSubmitQuestion
,
onRecommendLoadingChange
,
onWorkflowSubmit
,
isWorkflowSubmitting
,
allItems
=
[]
})
=>
{
const
[
isShowRecommend
,
setIsShowRecommend
]
=
useState
(
false
)
const
[
isShowRecommend
,
setIsShowRecommend
]
=
useState
(
false
)
const
[
recommendUseAnswer
,
setRecommendUseAnswer
]
=
useState
<
Answer
>
()
const
[
recommendUseAnswer
,
setRecommendUseAnswer
]
=
useState
<
Answer
>
()
const
[
innerRecord
,
setInnerRecord
]
=
useState
<
ChatRecord
>
(
record
)
const
[
innerRecord
,
setInnerRecord
]
=
useState
<
ChatRecord
>
(
record
)
...
@@ -58,9 +59,37 @@ export const ChatAnswerBox: React.FC<ChatAnswerBoxProps> = ({ record, showIndex,
...
@@ -58,9 +59,37 @@ export const ChatAnswerBox: React.FC<ChatAnswerBoxProps> = ({ record, showIndex,
{
innerRecord
.
answerList
.
map
((
item
,
index
)
=>
{
{
innerRecord
.
answerList
.
map
((
item
,
index
)
=>
{
// 当前默认始终展示点赞 / 点踩 / 复制等操作区(是否展示由下层基于卡片类型自行决定)
// 当前默认始终展示点赞 / 点踩 / 复制等操作区(是否展示由下层基于卡片类型自行决定)
const
shouldHideOperate
=
false
const
shouldHideOperate
=
false
// 如果 firstQaFlag 为 true 且存在 workflow 卡片,隐藏整个 chatItem(表单会自动提交,用户不需要看到这次的结果)
// 但保留组件的渲染,确保 CardWorkflowForm 的自动提交逻辑能够执行
const
hasWorkflowCard
=
(
item
.
cardList
||
[]).
some
(
attachment
=>
attachment
.
type
===
'card-workflow'
)
const
shouldHideChatItem
=
item
.
firstQaFlag
===
true
&&
hasWorkflowCard
// 创建包装函数,从会话历史中找到最后一个有 workFlowSessionId 的答案,并在追问时传递
const
handleSubmitQuestionWithWorkflow
=
(
question
:
string
,
productCode
?:
string
)
=>
{
// 从会话历史中找到最后一个有 workFlowSessionId 的答案(从后往前查找)
let
lastWorkFlowSessionId
:
string
|
undefined
let
lastRecordId
:
string
|
undefined
for
(
let
i
=
allItems
.
length
-
1
;
i
>=
0
;
i
--
)
{
const
historyItem
=
allItems
[
i
]
if
(
historyItem
.
role
===
'ai'
&&
historyItem
.
answerList
?.[
0
]?.
workFlowSessionId
)
{
lastWorkFlowSessionId
=
historyItem
.
answerList
[
0
].
workFlowSessionId
lastRecordId
=
historyItem
.
answerList
[
0
].
recordId
break
}
}
// 调用父组件传递的 onSubmitQuestion,传递 workFlowSessionId 和 recordId
onSubmitQuestion
(
question
,
productCode
,
lastWorkFlowSessionId
,
lastRecordId
)
}
return
(
return
(
index
===
showIndex
&&
(
index
===
showIndex
&&
(
<
div
className=
"chatItemBotContainer w-full"
key=
{
`${item.recordId}-${index}`
}
>
<
div
className=
"chatItemBotContainer w-full"
key=
{
`${item.recordId}-${index}`
}
style=
{
shouldHideChatItem
?
{
visibility
:
'hidden'
,
height
:
0
,
overflow
:
'hidden'
,
margin
:
0
,
padding
:
0
}
:
undefined
}
>
<
div
className=
"flex"
>
<
div
className=
"flex"
>
<
Avatar
<
Avatar
className=
"sm:mr-[20px] hidden sm:block flex-shrink-0"
className=
"sm:mr-[20px] hidden sm:block flex-shrink-0"
...
@@ -75,7 +104,7 @@ export const ChatAnswerBox: React.FC<ChatAnswerBoxProps> = ({ record, showIndex,
...
@@ -75,7 +104,7 @@ export const ChatAnswerBox: React.FC<ChatAnswerBoxProps> = ({ record, showIndex,
<
div
className=
"content"
>
<
div
className=
"content"
>
{
item
.
isShow
&&
(
{
item
.
isShow
&&
(
<
ChatAnswerShower
<
ChatAnswerShower
onSubmitQuestion=
{
onSubmitQuestion
}
onSubmitQuestion=
{
handleSubmitQuestionWithWorkflow
}
isLastAnswer=
{
isLastAnswer
}
isLastAnswer=
{
isLastAnswer
}
answer=
{
item
}
answer=
{
item
}
hideOperate=
{
shouldHideOperate
}
hideOperate=
{
shouldHideOperate
}
...
@@ -86,7 +115,7 @@ export const ChatAnswerBox: React.FC<ChatAnswerBoxProps> = ({ record, showIndex,
...
@@ -86,7 +115,7 @@ export const ChatAnswerBox: React.FC<ChatAnswerBoxProps> = ({ record, showIndex,
)
}
)
}
{
!
item
.
isShow
&&
!
item
.
isChatMaxCount
&&
(
{
!
item
.
isShow
&&
!
item
.
isChatMaxCount
&&
(
<
ChatAnswerParser
<
ChatAnswerParser
onSubmitQuestion=
{
onSubmitQuestion
}
onSubmitQuestion=
{
handleSubmitQuestionWithWorkflow
}
isLastAnswer=
{
isLastAnswer
}
isLastAnswer=
{
isLastAnswer
}
isStopTyping=
{
item
.
isStopTyping
}
isStopTyping=
{
item
.
isStopTyping
}
onTyping=
{
handleTyping
}
onTyping=
{
handleTyping
}
...
@@ -117,7 +146,10 @@ export const ChatAnswerBox: React.FC<ChatAnswerBoxProps> = ({ record, showIndex,
...
@@ -117,7 +146,10 @@ export const ChatAnswerBox: React.FC<ChatAnswerBoxProps> = ({ record, showIndex,
{
isLastAnswer
&&
!
item
.
isChatMaxCount
&&
isShowRecommend
&&
recommendUseAnswer
&&
(
{
isLastAnswer
&&
!
item
.
isChatMaxCount
&&
isShowRecommend
&&
recommendUseAnswer
&&
(
<
ChatAnswerRecommend
<
ChatAnswerRecommend
onSubmitQuestion=
{
onSubmitQuestion
}
onSubmitQuestion=
{
(
question
)
=>
{
// 使用 handleSubmitQuestionWithWorkflow,它会从会话历史中查找 workFlowSessionId
handleSubmitQuestionWithWorkflow
(
question
)
}
}
answer=
{
recommendUseAnswer
}
answer=
{
recommendUseAnswer
}
onLoadingChange=
{
onRecommendLoadingChange
}
onLoadingChange=
{
onRecommendLoadingChange
}
/>
/>
...
...
src/pages/Chat/components/ChatItem/ChatAnswerParser.tsx
View file @
eb862599
...
@@ -14,7 +14,7 @@ interface ChatAnswerParserProps {
...
@@ -14,7 +14,7 @@ interface ChatAnswerParserProps {
isLastAnswer
:
boolean
isLastAnswer
:
boolean
onTyping
:
()
=>
void
onTyping
:
()
=>
void
onComplate
:
()
=>
void
onComplate
:
()
=>
void
onSubmitQuestion
:
(
question
:
string
,
productCode
?:
string
)
=>
void
onSubmitQuestion
:
(
question
:
string
,
productCode
?:
string
,
workFlowSessionId
?:
string
,
recordId
?:
string
)
=>
void
/** 是否在当前回答中隐藏点赞/点踩/复制按钮(例如策略页自动分析、重新分析) */
/** 是否在当前回答中隐藏点赞/点踩/复制按钮(例如策略页自动分析、重新分析) */
hideOperate
?:
boolean
hideOperate
?:
boolean
onWorkflowSubmit
?:
(
paramMap
:
Record
<
string
,
string
>
,
recordId
?:
string
)
=>
void
onWorkflowSubmit
?:
(
paramMap
:
Record
<
string
,
string
>
,
recordId
?:
string
)
=>
void
...
@@ -178,31 +178,24 @@ export const ChatAnswerParser: React.FC<ChatAnswerParserProps> = ({ isLastAnswer
...
@@ -178,31 +178,24 @@ export const ChatAnswerParser: React.FC<ChatAnswerParserProps> = ({ isLastAnswer
const
shouldHideOperate
=
hideOperateByCard
||
hideOperate
const
shouldHideOperate
=
hideOperateByCard
||
hideOperate
// 如果 firstQaFlag 为 true 且存在 workflow 卡片,隐藏答案文本(表单会自动提交,用户不需要看到这次的结果)
// 但保留 ChatAnswerAttachment 的渲染,确保 CardWorkflowForm 的自动提交逻辑能够执行
const
hasWorkflowCard
=
(
answer
.
cardList
||
[]).
some
(
attachment
=>
attachment
.
type
===
'card-workflow'
)
const
shouldHideAnswerText
=
answer
.
firstQaFlag
===
true
&&
hasWorkflowCard
return
(
return
(
<
div
className=
"answerParser"
>
<
div
className=
"answerParser"
>
{
!
shouldHideAnswerText
&&
(
<
div
className=
"mb-[8px]"
>
<
div
className=
"mb-[8px]"
>
{
/* <Chip color="primary" className="mb-[12px]">{answer.step?.message}</Chip> */
}
{
/* <Chip color="primary" className="mb-[12px]">{answer.step?.message}</Chip> */
}
{
answer
.
step
?.
step
===
'answering'
&&
(
{
answer
.
step
?.
step
===
'answering'
&&
(
<
Chip
color=
"warning"
variant=
"flat"
>
<
Chip
color=
"warning"
variant=
"flat"
>
{
answer
.
step
?.
message
}
{
answer
.
step
?.
message
}
</
Chip
>
</
Chip
>
)
}
)
}
{
answer
.
step
?.
step
===
'finished'
&&
(
{
answer
.
step
?.
step
===
'finished'
&&
(
<
Chip
color=
"primary"
variant=
"flat"
startContent=
{
<
CheckIcon
/>
}
>
<
Chip
color=
"primary"
variant=
"flat"
startContent=
{
<
CheckIcon
/>
}
>
{
answer
.
step
?.
message
}
{
answer
.
step
?.
message
}
</
Chip
>
</
Chip
>
)
}
)
}
</
div
>
</
div
>
)
}
{
!!
displayedText
.
length
&&
(
{
!!
displayedText
.
length
&&
!
shouldHideAnswerText
&&
(
<
div
style=
{
{
background
:
'#F7FAFD'
}
}
className=
{
answer
.
cardList
?.
length
?
'mb-[20px]'
:
''
}
>
<
div
style=
{
{
background
:
'#F7FAFD'
}
}
className=
{
answer
.
cardList
?.
length
?
'mb-[20px]'
:
''
}
>
<
MarkdownDetail
>
<
MarkdownDetail
>
{
displayedText
}
{
displayedText
}
...
@@ -224,9 +217,9 @@ export const ChatAnswerParser: React.FC<ChatAnswerParserProps> = ({ isLastAnswer
...
@@ -224,9 +217,9 @@ export const ChatAnswerParser: React.FC<ChatAnswerParserProps> = ({ isLastAnswer
)
}
)
}
{
/* 操作区:仅根据卡片类型 / 上层显式 hideOperate 控制是否展示 */
}
{
/* 操作区:仅根据卡片类型 / 上层显式 hideOperate 控制是否展示 */
}
{
!
isTyping
&&
!
shouldHideOperate
&&
!
shouldHideAnswerText
&&
<
ChatAnswerOperate
answer=
{
answer
}
/>
}
{
!
isTyping
&&
!
shouldHideOperate
&&
<
ChatAnswerOperate
answer=
{
answer
}
/>
}
{
!
isTyping
&&
!
shouldHideAnswerText
&&
<
div
className=
"flex text-[10px] right-[16px] text-[#d0d1d2] bottom-[4px]"
>
AI生成
</
div
>
}
{
!
isTyping
&&
<
div
className=
"flex text-[10px] right-[16px] text-[#d0d1d2] bottom-[4px]"
>
AI生成
</
div
>
}
</
div
>
</
div
>
)
)
}
}
src/pages/Chat/components/ChatItem/ChatAnswerShower.tsx
View file @
eb862599
...
@@ -8,7 +8,7 @@ import { MarkdownDetail } from '@/components/MarkdownDetail'
...
@@ -8,7 +8,7 @@ import { MarkdownDetail } from '@/components/MarkdownDetail'
interface
ChatAnswerShowerProps
{
interface
ChatAnswerShowerProps
{
answer
:
Answer
answer
:
Answer
isLastAnswer
:
boolean
isLastAnswer
:
boolean
onSubmitQuestion
:
(
question
:
string
)
=>
void
onSubmitQuestion
:
(
question
:
string
,
productCode
?:
string
,
workFlowSessionId
?:
string
,
recordId
?:
string
)
=>
void
hideOperate
?:
boolean
hideOperate
?:
boolean
onWorkflowSubmit
?:
(
paramMap
:
Record
<
string
,
string
>
,
recordId
?:
string
)
=>
void
onWorkflowSubmit
?:
(
paramMap
:
Record
<
string
,
string
>
,
recordId
?:
string
)
=>
void
isWorkflowSubmitting
?:
boolean
isWorkflowSubmitting
?:
boolean
...
@@ -19,14 +19,9 @@ export const ChatAnswerShower: React.FC<ChatAnswerShowerProps> = ({ answer, isLa
...
@@ -19,14 +19,9 @@ export const ChatAnswerShower: React.FC<ChatAnswerShowerProps> = ({ answer, isLa
const
hideOperateByCard
=
(
answer
.
cardList
||
[]).
some
(
attachment
=>
attachment
.
type
===
'box'
||
attachment
?.
type
?.
includes
(
'card-'
))
const
hideOperateByCard
=
(
answer
.
cardList
||
[]).
some
(
attachment
=>
attachment
.
type
===
'box'
||
attachment
?.
type
?.
includes
(
'card-'
))
const
hideOperate
=
hideOperateByCard
||
hideOperateProp
const
hideOperate
=
hideOperateByCard
||
hideOperateProp
// 如果 firstQaFlag 为 true 且存在 workflow 卡片,隐藏答案文本(表单会自动提交,用户不需要看到这次的结果)
// 但保留 ChatAnswerAttachment 的渲染,确保 CardWorkflowForm 的自动提交逻辑能够执行
const
hasWorkflowCard
=
(
answer
.
cardList
||
[]).
some
(
attachment
=>
attachment
.
type
===
'card-workflow'
)
const
shouldHideAnswerText
=
answer
.
firstQaFlag
===
true
&&
hasWorkflowCard
return
(
return
(
<
div
className=
"answerShower"
>
<
div
className=
"answerShower"
>
{
answer
.
answer
&&
!
shouldHideAnswerText
&&
(
{
answer
.
answer
&&
(
<
div
className=
{
answer
.
cardList
?.
length
?
'mb-[12px] sm:mb-[20px]'
:
''
}
>
<
div
className=
{
answer
.
cardList
?.
length
?
'mb-[12px] sm:mb-[20px]'
:
''
}
>
<
MarkdownDetail
>
<
MarkdownDetail
>
{
formatMarkdown
(
answer
.
answer
||
''
)
}
{
formatMarkdown
(
answer
.
answer
||
''
)
}
...
@@ -44,8 +39,8 @@ export const ChatAnswerShower: React.FC<ChatAnswerShowerProps> = ({ answer, isLa
...
@@ -44,8 +39,8 @@ export const ChatAnswerShower: React.FC<ChatAnswerShowerProps> = ({ answer, isLa
/>
/>
)
}
)
}
{
/* 操作区:仅根据卡片类型 / 上层显式 hideOperate 控制是否展示 */
}
{
/* 操作区:仅根据卡片类型 / 上层显式 hideOperate 控制是否展示 */
}
{
!
hideOperate
&&
!
shouldHideAnswerText
&&
<
ChatAnswerOperate
answer=
{
answer
}
/>
}
{
!
hideOperate
&&
<
ChatAnswerOperate
answer=
{
answer
}
/>
}
{
!
shouldHideAnswerText
&&
<
div
className=
"flex text-[10px] right-[16px] text-[#d0d1d2] bottom-[4px]"
>
AI生成
</
div
>
}
<
div
className=
"flex text-[10px] right-[16px] text-[#d0d1d2] bottom-[4px]"
>
AI生成
</
div
>
</
div
>
</
div
>
)
)
}
}
src/pages/ChatTactics/TacticsChat.tsx
View file @
eb862599
...
@@ -500,8 +500,27 @@ export const TacticsChat: React.FC = () => {
...
@@ -500,8 +500,27 @@ export const TacticsChat: React.FC = () => {
if
(
extra
?.
recordId
)
{
if
(
extra
?.
recordId
)
{
requestBody
.
recordId
=
extra
.
recordId
requestBody
.
recordId
=
extra
.
recordId
}
}
if
(
extra
?.
workFlowSessionId
)
{
requestBody
.
workFlowSessionId
=
extra
.
workFlowSessionId
// workFlowSessionId 的传递逻辑:
// 1. 如果是重新分析(isReanalyze === true),不传递 workFlowSessionId
// 2. 优先使用 extra 中的值
// 3. 如果都没有,从会话历史中找到最后一个有 workFlowSessionId 的答案
const
isReanalyze
=
extra
?.
isReanalyze
===
true
if
(
!
isReanalyze
)
{
if
(
extra
?.
workFlowSessionId
)
{
requestBody
.
workFlowSessionId
=
extra
.
workFlowSessionId
}
else
{
// 从会话历史中找到最后一个有 workFlowSessionId 的答案
// 注意:这里使用 allItems 的当前值(在添加新记录之前),所以需要从倒数第二个开始查找
for
(
let
i
=
allItems
.
length
-
1
;
i
>=
0
;
i
--
)
{
const
item
=
allItems
[
i
]
if
(
item
.
role
===
'ai'
&&
item
.
answerList
?.[
0
]?.
workFlowSessionId
)
{
requestBody
.
workFlowSessionId
=
item
.
answerList
[
0
].
workFlowSessionId
break
}
}
}
}
}
// 调试日志:检查最终请求参数
// 调试日志:检查最终请求参数
console
.
log
(
'[TacticsChat] handleSubmitQuestion: final requestBody'
,
{
console
.
log
(
'[TacticsChat] handleSubmitQuestion: final requestBody'
,
{
...
@@ -1036,7 +1055,15 @@ export const TacticsChat: React.FC = () => {
...
@@ -1036,7 +1055,15 @@ export const TacticsChat: React.FC = () => {
// 提供给 ChatAnswerBox/推荐问题的提交方法,保持与手动提问一致的 recordType 逻辑
// 提供给 ChatAnswerBox/推荐问题的提交方法,保持与手动提问一致的 recordType 逻辑
const
handleAnswerBoxSubmit
=
useCallback
(
const
handleAnswerBoxSubmit
=
useCallback
(
(
question
:
string
,
productCode
?:
string
)
=>
{
(
question
:
string
,
productCode
?:
string
,
workFlowSessionId
?:
string
,
recordId
?:
string
)
=>
{
const
extraParams
:
any
=
{}
if
(
workFlowSessionId
)
{
extraParams
.
workFlowSessionId
=
workFlowSessionId
}
if
(
recordId
)
{
extraParams
.
recordId
=
recordId
}
if
(
orderMeta
)
{
if
(
orderMeta
)
{
return
handleSubmitQuestion
(
return
handleSubmitQuestion
(
question
,
question
,
...
@@ -1048,6 +1075,7 @@ export const TacticsChat: React.FC = () => {
...
@@ -1048,6 +1075,7 @@ export const TacticsChat: React.FC = () => {
includeQuestion
:
true
,
includeQuestion
:
true
,
includeTacticsMeta
:
false
,
includeTacticsMeta
:
false
,
includeOrderMeta
:
true
,
includeOrderMeta
:
true
,
...
extraParams
,
},
},
)
)
}
}
...
@@ -1064,6 +1092,7 @@ export const TacticsChat: React.FC = () => {
...
@@ -1064,6 +1092,7 @@ export const TacticsChat: React.FC = () => {
includeQuestion
:
true
,
includeQuestion
:
true
,
includeTacticsMeta
:
false
,
includeTacticsMeta
:
false
,
includeUserMeta
:
true
,
includeUserMeta
:
true
,
...
extraParams
,
},
},
)
)
}
}
...
@@ -1076,6 +1105,7 @@ export const TacticsChat: React.FC = () => {
...
@@ -1076,6 +1105,7 @@ export const TacticsChat: React.FC = () => {
recordType
:
'A01'
,
recordType
:
'A01'
,
includeQuestion
:
true
,
includeQuestion
:
true
,
includeTacticsMeta
:
true
,
includeTacticsMeta
:
true
,
...
extraParams
,
},
},
)
)
},
},
...
@@ -1197,6 +1227,7 @@ export const TacticsChat: React.FC = () => {
...
@@ -1197,6 +1227,7 @@ export const TacticsChat: React.FC = () => {
onRecommendLoadingChange=
{
index
===
allItems
.
length
-
1
?
setIsRecommendLoading
:
undefined
}
onRecommendLoadingChange=
{
index
===
allItems
.
length
-
1
?
setIsRecommendLoading
:
undefined
}
onWorkflowSubmit=
{
handleWorkflowSubmit
}
onWorkflowSubmit=
{
handleWorkflowSubmit
}
isWorkflowSubmitting=
{
isAsking
}
isWorkflowSubmitting=
{
isAsking
}
allItems=
{
allItems
}
/>
/>
)
}
)
}
</
div
>
</
div
>
...
...
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