初始化模版工程
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
import { useState, useEffect, memo } from 'react'
|
||||
import { Loader2 } from 'lucide-react'
|
||||
import { Image } from '@/components/ui/image'
|
||||
import { ImagePreview } from '@/components/ui/image-preview'
|
||||
import type { HandleImageAttachmentClick, ImageAttachment, TaskArtifact } from '../../types'
|
||||
import { useNovaKit } from '../../context/useNovaKit'
|
||||
|
||||
export interface ImageAttachmentItemProps {
|
||||
image: ImageAttachment
|
||||
assetsType: 'assistant' | 'user'
|
||||
onClick?: HandleImageAttachmentClick
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否需要加载 OSS URL
|
||||
*/
|
||||
function needsOssUrl(image: ImageAttachment): boolean {
|
||||
if (image.url && image.url.startsWith('http')) {
|
||||
return false
|
||||
}
|
||||
return !!(image.path || image.url)
|
||||
}
|
||||
|
||||
/**
|
||||
* 图片附件展示组件
|
||||
*/
|
||||
export const ImageAttachmentItem = memo(function ImageAttachmentItem({
|
||||
image,
|
||||
assetsType,
|
||||
onClick,
|
||||
}: ImageAttachmentItemProps) {
|
||||
const { api } = useNovaKit()
|
||||
const initialUrl = image.url?.startsWith('http') ? image.url : ''
|
||||
const [url, setUrl] = useState<string>(initialUrl)
|
||||
const [loading, setLoading] = useState(needsOssUrl(image))
|
||||
|
||||
useEffect(() => {
|
||||
if (image.url && image.url.startsWith('http')) {
|
||||
return
|
||||
}
|
||||
|
||||
const filePath = image.path || image.url || image.file_url
|
||||
if (filePath) {
|
||||
api
|
||||
.getArtifactUrl?.({ ...image, path: filePath } as TaskArtifact)
|
||||
.then((res: { data: string }) => {
|
||||
const fileUrls = res?.data
|
||||
if (fileUrls) {
|
||||
setUrl(fileUrls)
|
||||
image.url = fileUrls
|
||||
}
|
||||
})
|
||||
.catch((err: Error) => {
|
||||
console.error('获取图片 URL 失败:', err)
|
||||
})
|
||||
.finally(() => {
|
||||
setLoading(false)
|
||||
})
|
||||
}
|
||||
}, [image, image.url, image.path, api])
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="flex items-center justify-center min-w-32 h-full min-h-32 rounded-lg">
|
||||
<Loader2 className="w-6 h-6 animate-spin text-muted-foreground" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (!url) return null
|
||||
|
||||
const handleClick = () => {
|
||||
if (onClick) {
|
||||
onClick({ ...image, url: url || image.url }, assetsType)
|
||||
}
|
||||
}
|
||||
|
||||
if (onClick) {
|
||||
return (
|
||||
<div onClick={handleClick} className="cursor-pointer">
|
||||
<Image
|
||||
src={url}
|
||||
alt={image.file_name || '图片'}
|
||||
className="max-w-full max-h-[300px] rounded-lg hover:opacity-80 transition-opacity"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-center w-full h-full">
|
||||
<ImagePreview src={url} alt={image.file_name || '图片'}>
|
||||
<Image
|
||||
src={url}
|
||||
alt={image.file_name || '图片'}
|
||||
className="max-w-full max-h-[300px] rounded-lg hover:opacity-80 transition-opacity"
|
||||
/>
|
||||
</ImagePreview>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
Reference in New Issue
Block a user