81 lines
2.1 KiB
TypeScript
81 lines
2.1 KiB
TypeScript
import React from 'react'
|
|
import { cn } from '@/utils/cn'
|
|
import type { Attachment, ImageAttachment, BaseEvent, HandleImageAttachmentClick } from '../../types'
|
|
import { AttachmentItem } from './AttachmentItem'
|
|
import { ImageAttachmentItem } from './ImageAttachmentItem'
|
|
|
|
export interface UserMessageProps {
|
|
base?: BaseEvent
|
|
attachment?: Attachment[]
|
|
imageAttachment?: ImageAttachment[]
|
|
loading?: boolean
|
|
isUserInput: boolean
|
|
showTemplate?: boolean
|
|
onAttachmentClick?: (attachment: Attachment) => void
|
|
onImageAttachmentClick?: HandleImageAttachmentClick
|
|
}
|
|
|
|
/**
|
|
* 用户消息附件组件 - 展示用户上传的文件/图片,对应 next-agent UserMessage
|
|
*/
|
|
function InnerUserMessage({
|
|
attachment,
|
|
imageAttachment,
|
|
loading,
|
|
isUserInput,
|
|
onAttachmentClick,
|
|
onImageAttachmentClick,
|
|
}: UserMessageProps) {
|
|
const hasImages = !!(imageAttachment?.length)
|
|
const hasFiles = !!(attachment?.length)
|
|
|
|
if (!hasImages && !hasFiles) return null
|
|
|
|
return (
|
|
<div
|
|
className={cn(
|
|
'flex flex-col rounded-xl mt-2 mb-6 px-3',
|
|
{ 'opacity-60': loading },
|
|
isUserInput ? 'items-end' : 'items-start',
|
|
)}
|
|
>
|
|
{hasImages && (
|
|
<div
|
|
className={cn(
|
|
'flex flex-wrap gap-2 mb-2',
|
|
isUserInput ? 'justify-end' : 'justify-start',
|
|
)}
|
|
>
|
|
{imageAttachment!.map((img, i) => (
|
|
<ImageAttachmentItem
|
|
assetsType="user"
|
|
key={img.url || img.path || i}
|
|
image={img}
|
|
onClick={onImageAttachmentClick}
|
|
/>
|
|
))}
|
|
</div>
|
|
)}
|
|
{hasFiles && (
|
|
<div
|
|
className={cn(
|
|
'flex flex-wrap gap-2',
|
|
isUserInput ? 'justify-end' : 'justify-start',
|
|
)}
|
|
>
|
|
{attachment!.map((att, i) => (
|
|
<AttachmentItem
|
|
key={att.file_id || att.file_url || i}
|
|
attachment={att}
|
|
onClick={onAttachmentClick}
|
|
/>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export const UserMessage = React.memo(InnerUserMessage)
|
|
export default UserMessage
|