返回 AiToEarn
1 /**
2 * MediaAddToReferenceAction - 图片资源追加到 AI 参考文件
3 * 在纯图片资源卡片上提供一键追加到 AI 批量生成输入参考文件的入口
4 */
5
6 'use client'
7
8 import type { MediaItem } from '@/api/materials/material.types'
9 import { ImagePlus } from 'lucide-react'
10 import { memo, useCallback } from 'react'
11 import { useTransClient } from '@/app/i18n/client'
12 import { Button } from '@/components/ui/button'
13 import { useDraftBoxConfigStore } from '@/store/draft-box/draftBoxConfigStore'
14 import { cn } from '@/utils/className'
15 import { getOssUrl } from '@/utils/oss'
16 import { toast } from '@/utils/ui/toast'
17
18 interface MediaAddToReferenceActionProps {
19 media: MediaItem
20 groupId: string
21 maxImages: number
22 }
23
24 export const MediaAddToReferenceAction = memo(({
25 media,
26 groupId,
27 maxImages,
28 }: MediaAddToReferenceActionProps) => {
29 const { t } = useTransClient('brandPromotion')
30
31 const handleAddToReference = useCallback(() => {
32 if (media.type !== 'img') {
33 return
34 }
35
36 const { getConfig, appendPersistedMedias } = useDraftBoxConfigStore.getState()
37 const currentConfig = getConfig(groupId)
38 const persistedImageUrls = (currentConfig.persistedMedias ?? [])
39 .filter(item => item.type === 'image')
40 .map(item => getOssUrl(item.url))
41 const currentImageCount = persistedImageUrls.length
42 const normalizedUrl = getOssUrl(media.url)
43
44 if (persistedImageUrls.includes(normalizedUrl)) {
45 toast.info(t('detail.draftImagesAlreadyInReference'))
46 return
47 }
48
49 const availableCount = Math.max(0, maxImages - currentImageCount)
50 if (availableCount === 0) {
51 toast.warning(t('detail.imageCountExceeded', { max: maxImages }))
52 return
53 }
54
55 const { added } = appendPersistedMedias(groupId, [{
56 id: `media-reference-${media._id}`,
57 url: normalizedUrl,
58 type: 'image',
59 name: media.title || undefined,
60 }])
61
62 if (added === 0) {
63 toast.info(t('detail.draftImagesAlreadyInReference'))
64 return
65 }
66
67 toast.success(t('detail.draftImagesAddedToReference', { count: added }))
68 }, [groupId, maxImages, media, t])
69
70 if (media.type !== 'img') {
71 return null
72 }
73
74 return (
75 <Button
76 type="button"
77 onClick={handleAddToReference}
78 className={cn(
79 'h-9 rounded-full border border-primary/25 bg-background/95 px-3 text-xs font-semibold text-foreground shadow-lg shadow-primary/15 backdrop-blur-md',
80 'cursor-pointer gap-1.5 transition-all duration-200 hover:border-primary/40 hover:bg-background hover:shadow-xl hover:shadow-primary/20',
81 )}
82 >
83 <ImagePlus className="h-4 w-4 text-primary" />
84 <span>{t('detail.addDraftImagesToReference')}</span>
85 </Button>
86 )
87 })
88
89 MediaAddToReferenceAction.displayName = 'MediaAddToReferenceAction'
90
90 lines Plain Text