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
f9032e3b
Commit
f9032e3b
authored
Aug 15, 2024
by
HoMeTown
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 处理box附件
parent
8adc1d19
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
85 additions
and
36 deletions
+85
-36
src/pages/Chat/Chat.tsx
+2
-1
src/pages/Chat/components/ChatItem/ChatAnswerAttchment.tsx
+36
-4
src/pages/Chat/components/ChatItem/ChatAnswerBox.tsx
+9
-10
src/pages/Chat/components/ChatItem/ChatAnswerParser.tsx
+17
-6
src/pages/Chat/components/ChatItem/ChatAnswerShower.tsx
+13
-14
src/pages/Collect/Collect.tsx
+1
-1
src/types/chat.ts
+7
-0
No files found.
src/pages/Chat/Chat.tsx
View file @
f9032e3b
...
...
@@ -31,7 +31,7 @@ export const Chat: React.FC = () => {
const
scrollableRef
=
useRef
<
HTMLDivElement
|
any
>
(
null
)
const
position
=
useScroll
(
scrollableRef
)
const
handleSubmitQuestion
=
async
(
question
:
string
)
=>
{
const
handleSubmitQuestion
=
async
(
question
:
string
,
productCode
?:
string
)
=>
{
const
isNew
=
allItems
.
length
<=
1
dispatch
(
setIsAsking
(
true
))
// 添加用户提问的问题
...
...
@@ -64,6 +64,7 @@ export const Chat: React.FC = () => {
question
,
conversationId
:
id
,
stream
:
true
,
productCode
,
},
(
msg
)
=>
{
if
(
msg
.
type
===
'DATA'
)
{
...
...
src/pages/Chat/components/ChatItem/ChatAnswerAttchment.tsx
View file @
f9032e3b
import
{
Link
}
from
'@nextui-org/react'
import
{
Button
,
Link
}
from
'@nextui-org/react'
import
{
motion
}
from
'framer-motion'
import
type
{
Answer
}
from
'@/types/chat'
import
AnswerProDetailIcon
from
'@/assets/svg/answerProDetail.svg?react'
interface
ChatAnswerAttachmentProps
{
answer
:
Answer
isLastAnswer
?:
boolean
onSubmitQuestion
?:
(
question
:
string
,
productCode
?:
string
)
=>
void
}
export
const
ChatAnswerAttachment
:
React
.
FC
<
ChatAnswerAttachmentProps
>
=
({
answer
})
=>
{
export
const
ChatAnswerAttachment
:
React
.
FC
<
ChatAnswerAttachmentProps
>
=
({
answer
,
isLastAnswer
,
onSubmitQuestion
})
=>
{
const
handleClickBoxItem
=
(
produceName
:
string
,
productCode
:
string
)
=>
{
if
(
onSubmitQuestion
)
{
onSubmitQuestion
(
produceName
,
productCode
)
}
}
return
(
<
div
className=
"attachmentList flex flex-col gap-[20px]
mt-[20px]
"
>
<
div
className=
"attachmentList flex flex-col gap-[20px]"
>
{
answer
.
attachmentList
&&
answer
.
attachmentList
.
map
((
attachment
,
index
)
=>
(
<
div
key=
{
`${attachment.type}_${index}`
}
>
{
/* 附件:product-detail */
}
{
attachment
.
type
===
'product-detail'
&&
(
<
div
className=
"bg-[#29B6FD0A] text-[14px] text-primary py-[4px] px-[16px] w-fit flex items-center"
>
...
...
@@ -43,6 +50,31 @@ export const ChatAnswerAttachment: React.FC<ChatAnswerAttachmentProps> = ({ answ
</
div
>
)
}
{
/* 附件:选择 box */
}
{
attachment
.
type
===
'box'
&&
attachment
.
content
.
productList
.
length
!==
0
&&
(
<
div
>
<
div
className=
"mb-[12px]"
>
{
attachment
.
description
}
</
div
>
<
ul
className=
"flex flex-col gap-[8px]"
>
{
attachment
.
content
.
productList
.
map
(
product
=>
(
// <div key=
{
product
.
productCode
}
>
{
product
.
productName
}<
/
div
>
<
motion
.
li
key=
{
product
.
productCode
}
>
<
Button
onClick=
{
()
=>
handleClickBoxItem
(
product
.
productName
,
product
.
productCode
)
}
isDisabled=
{
!
isLastAnswer
}
color=
"primary"
variant=
"light"
className=
"text-left bg-[#F7FCFF] w-full text-[#333] rounded-[23px] data-[hover=true]:bg-[#E5F6FF] data-[hover=true]:text-primary"
>
<
div
className=
"w-full text-nowrap text-ellipsis overflow-hidden"
>
<
span
className=
"ml-[8px]"
>
{
product
.
productName
}
</
span
>
</
div
>
</
Button
>
</
motion
.
li
>
))
}
</
ul
>
</
div
>
)
}
</
div
>
))
}
</
div
>
...
...
src/pages/Chat/components/ChatItem/ChatAnswerBox.tsx
View file @
f9032e3b
...
...
@@ -14,7 +14,7 @@ interface ChatAnswerBoxProps {
showIndex
:
number
isLastAnswer
:
boolean
index
:
number
onSubmitQuestion
:
(
question
:
string
)
=>
void
onSubmitQuestion
:
(
question
:
string
,
productCode
?:
string
)
=>
void
}
export
const
ChatAnswerBox
:
React
.
FC
<
ChatAnswerBoxProps
>
=
({
record
,
showIndex
,
isLastAnswer
,
onSubmitQuestion
})
=>
{
...
...
@@ -55,15 +55,14 @@ export const ChatAnswerBox: React.FC<ChatAnswerBoxProps> = ({ record, showIndex,
<
motion
.
div
className=
"ml-[20px] bg-white rounded-[20px] box-border px-[24px] py-[20px]"
>
{
item
.
answer
&&
(
<
div
className=
"content"
>
{
item
.
isShow
&&
<
ChatAnswerShower
answer=
{
item
}
/>
}
{
!
item
.
isShow
&&
<
ChatAnswerParser
isStopTyping=
{
item
.
isStopTyping
}
onTyping=
{
handleTyping
}
onComplate=
{
()
=>
handleComplate
(
item
)
}
answer=
{
item
}
/>
}
</
div
>
)
}
{
!
item
.
answer
&&
(
<
Spinner
size=
"sm"
/>
)
}
{
(
item
.
answer
?.
length
||
item
.
attachmentList
?.
length
)
?
(
<
div
className=
"content"
>
{
item
.
isShow
&&
<
ChatAnswerShower
onSubmitQuestion=
{
onSubmitQuestion
}
isLastAnswer=
{
isLastAnswer
}
answer=
{
item
}
/>
}
{
!
item
.
isShow
&&
<
ChatAnswerParser
onSubmitQuestion=
{
onSubmitQuestion
}
isLastAnswer=
{
isLastAnswer
}
isStopTyping=
{
item
.
isStopTyping
}
onTyping=
{
handleTyping
}
onComplate=
{
()
=>
handleComplate
(
item
)
}
answer=
{
item
}
/>
}
</
div
>
)
:
<
Spinner
size=
"sm"
/>
}
</
motion
.
div
>
<
div
className=
"w-[130px]"
></
div
>
</
div
>
...
...
src/pages/Chat/components/ChatItem/ChatAnswerParser.tsx
View file @
f9032e3b
...
...
@@ -9,15 +9,18 @@ import { fetchTerminateQuestion } from '@/api/chat'
interface
ChatAnswerParserProps
{
answer
:
Answer
isStopTyping
:
boolean
|
undefined
isLastAnswer
:
boolean
onTyping
:
()
=>
void
onComplate
:
()
=>
void
onSubmitQuestion
:
(
question
:
string
,
productCode
?:
string
)
=>
void
}
export
const
ChatAnswerParser
:
React
.
FC
<
ChatAnswerParserProps
>
=
({
onTyping
,
onComplate
,
answer
,
isStopTyping
})
=>
{
export
const
ChatAnswerParser
:
React
.
FC
<
ChatAnswerParserProps
>
=
({
isLastAnswer
,
onTyping
,
onComplate
,
answer
,
isStopTyping
,
onSubmitQuestion
})
=>
{
const
formatAnswer
=
formatMarkdown
(
answer
.
answer
||
''
)
const
[
displayedText
,
setDisplayedText
]
=
useState
(
''
)
const
[
currentIndex
,
setCurrentIndex
]
=
useState
(
0
)
const
[
isTyping
,
setIsTyping
]
=
useState
(
false
)
const
[
hideOperate
,
setHideOperate
]
=
useState
(
false
)
useEffect
(()
=>
{
if
(
isStopTyping
)
{
...
...
@@ -57,17 +60,25 @@ export const ChatAnswerParser: React.FC<ChatAnswerParserProps> = ({ onTyping, on
}
},
[
isStopTyping
])
useEffect
(()
=>
{
setHideOperate
(
answer
.
attachmentList
.
some
(
attachment
=>
attachment
.
type
===
'box'
))
},
[
answer
.
attachmentList
])
return
(
<
div
className=
"answerParser"
>
<
MarkdownDetail
>
{
displayedText
}
</
MarkdownDetail
>
{
!!
displayedText
.
length
&&
(
<
div
className=
{
answer
.
attachmentList
?.
length
?
'mb-[20px]'
:
''
}
>
<
MarkdownDetail
>
{
displayedText
}
</
MarkdownDetail
>
</
div
>
)
}
{
!
isTyping
&&
answer
.
attachmentList
&&
answer
.
attachmentList
?.
length
!==
0
&&
<
ChatAnswerAttachment
answer=
{
answer
}
/>
}
&&
<
ChatAnswerAttachment
isLastAnswer=
{
isLastAnswer
}
onSubmitQuestion=
{
onSubmitQuestion
}
answer=
{
answer
}
/>
}
{
!
isTyping
&&
<
ChatAnswerOperate
answer=
{
answer
}
/>
}
{
!
isTyping
&&
!
hideOperate
&&
<
ChatAnswerOperate
answer=
{
answer
}
/>
}
</
div
>
)
}
src/pages/Chat/components/ChatItem/ChatAnswerShower.tsx
View file @
f9032e3b
...
...
@@ -6,24 +6,23 @@ import { MarkdownDetail } from '@/components/MarkdownDetail'
interface
ChatAnswerShowerProps
{
answer
:
Answer
isLastAnswer
:
boolean
onSubmitQuestion
:
(
question
:
string
)
=>
void
}
export
const
ChatAnswerShower
:
React
.
FC
<
ChatAnswerShowerProps
>
=
({
answer
})
=>
{
export
const
ChatAnswerShower
:
React
.
FC
<
ChatAnswerShowerProps
>
=
({
answer
,
isLastAnswer
,
onSubmitQuestion
})
=>
{
const
hideOperate
=
answer
.
attachmentList
.
some
(
attachment
=>
attachment
.
type
===
'box'
)
return
(
<
div
className=
"answerShower"
>
<
MarkdownDetail
>
{
formatMarkdown
(
answer
.
answer
||
''
)
}
</
MarkdownDetail
>
{
/* <ReactMarkdown
rehypePlugins={[rehypeRaw, rehypeSanitize]}
remarkPlugins={[remarkGfm]}
className="markdown-content"
>
{formatMarkdown(answer.answer || '')}
</ReactMarkdown> */
}
{
answer
.
attachmentList
&&
answer
.
attachmentList
?.
length
!==
0
&&
<
ChatAnswerAttachment
answer=
{
answer
}
/>
}
<
ChatAnswerOperate
answer=
{
answer
}
/>
{
answer
.
answer
&&
(
<
div
className=
{
answer
.
attachmentList
?.
length
?
'mb-[20px]'
:
''
}
>
<
MarkdownDetail
>
{
formatMarkdown
(
answer
.
answer
||
''
)
}
</
MarkdownDetail
>
</
div
>
)
}
{
answer
.
attachmentList
&&
answer
.
attachmentList
?.
length
!==
0
&&
<
ChatAnswerAttachment
onSubmitQuestion=
{
onSubmitQuestion
}
isLastAnswer=
{
isLastAnswer
}
answer=
{
answer
}
/>
}
{
!
hideOperate
&&
<
ChatAnswerOperate
answer=
{
answer
}
/>
}
</
div
>
)
}
src/pages/Collect/Collect.tsx
View file @
f9032e3b
...
...
@@ -113,7 +113,7 @@ export const Collect: React.FC = () => {
<
div
className=
"mr-[20px]"
>
<
AIcon
/>
</
div
>
<
div
>
<
div
className=
"flex-1"
>
<
MarkdownDetail
>
{
formatMarkdown
(
item
.
answer
||
''
)
}
</
MarkdownDetail
>
...
...
src/types/chat.ts
View file @
f9032e3b
...
...
@@ -3,8 +3,15 @@ interface AttachmentContentDoc {
docName
:
string
}
interface
AttachmentContentProduct
{
productName
:
string
productCode
:
string
}
interface
AttachmentContent
{
docList
:
AttachmentContentDoc
[]
description
:
string
productList
:
AttachmentContentProduct
[]
}
export
interface
Attachment
{
...
...
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