import { useEffect, useRef, useState } from 'react'; import { Link2, Upload } from 'lucide-react'; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Spinner } from '@/components/ui/spinner'; import { notify } from '@/lib/notify'; import { cn } from '@/lib/utils'; import { api } from '../api/client'; import type { FriendLinkApply } from '../api/types'; import { getCachedSiteBranding } from '../hooks/useSiteBranding'; import { resolveFriendLinkLogo } from '../utils/friendLink'; import FriendLinkSiteInfo from './FriendLinkSiteInfo'; type LinkPlacement = 'homepage' | 'custom'; interface Props { open: boolean; onOpenChange: (open: boolean) => void; editApply?: FriendLinkApply | null; onSubmitted?: () => void; } /** 友链申请 / 修改弹窗 */ export default function FriendLinkApplyDialog({ open, onOpenChange, editApply, onSubmitted }: Props) { const [name, setName] = useState(''); const [url, setUrl] = useState(''); const [logo, setLogo] = useState(''); const [linkPlacement, setLinkPlacement] = useState('homepage'); const [reciprocalPageURL, setReciprocalPageURL] = useState(''); const [submitting, setSubmitting] = useState(false); const [uploadingLogo, setUploadingLogo] = useState(false); const fileRef = useRef(null); const isEdit = !!editApply?.id; const reset = () => { setName(''); setUrl(''); setLogo(''); setLinkPlacement('homepage'); setReciprocalPageURL(''); }; useEffect(() => { if (!open) return; if (editApply) { setName(editApply.name ?? ''); setUrl(editApply.url ?? ''); setLogo(editApply.logo ?? ''); const onHomepage = editApply.link_on_homepage !== false; setLinkPlacement(onHomepage ? 'homepage' : 'custom'); setReciprocalPageURL(onHomepage ? '' : (editApply.reciprocal_page_url ?? '')); } else { reset(); } }, [open, editApply]); const handleOpenChange = (next: boolean) => { if (!next) reset(); onOpenChange(next); }; const uploadLogo = async (file: File | undefined) => { if (!file) return; setUploadingLogo(true); try { const r = await api.uploadFriendLinkLogo(file); setLogo(r.url); notify.success('LOGO 已上传'); } catch (e: unknown) { notify.error(e instanceof Error ? e.message : '上传失败'); } finally { setUploadingLogo(false); if (fileRef.current) fileRef.current.value = ''; } }; const submit = async () => { const trimmedName = name.trim(); const trimmedURL = url.trim(); const trimmedLogo = logo.trim(); const trimmedReciprocal = reciprocalPageURL.trim(); if (!trimmedName || !trimmedURL) { notify.warning('请填写网站名称与网站链接'); return; } if (!/^https?:\/\//i.test(trimmedURL)) { notify.warning('网站链接需以 http:// 或 https:// 开头'); return; } if (!trimmedLogo) { notify.warning('请填写或上传网站 LOGO'); return; } if (linkPlacement === 'custom') { if (!trimmedReciprocal) { notify.warning('请填写添加本站链接的页面地址'); return; } if (!/^https?:\/\//i.test(trimmedReciprocal)) { notify.warning('回链页地址需以 http:// 或 https:// 开头'); return; } } const linkOnHomepage = linkPlacement === 'homepage'; const body = { name: trimmedName, url: trimmedURL, logo: trimmedLogo, link_on_homepage: linkOnHomepage, reciprocal_page_url: linkOnHomepage ? trimmedURL : trimmedReciprocal, }; setSubmitting(true); try { if (isEdit) { const r = await api.updateFriendLinkApply(editApply!.id, body); notify.success( editApply?.status === 'approved' ? `已更新并重新提交审核,友链已暂时从列表移除${r.message.includes('回链检测') ? ',回链检测将在后台进行' : ''}` : r.message, ); } else { const r = await api.applyFriendLink(body); notify.success(r.message); } onSubmitted?.(); handleOpenChange(false); } catch (e: unknown) { notify.error(e instanceof Error ? e.message : '提交失败'); } finally { setSubmitting(false); } }; const logoPreview = resolveFriendLinkLogo(logo.trim(), getCachedSiteBranding().site_url); return ( {isEdit ? '修改友链申请' : '申请本页友情链接'}
setName(e.target.value)} placeholder="请输入您的网站名称" maxLength={32} />
setUrl(e.target.value)} placeholder="请输入您的网站地址(以 http 开头)" maxLength={512} />
{linkPlacement === 'custom' && (
setReciprocalPageURL(e.target.value)} placeholder="如:https://您的域名/link.htm" maxLength={512} />

请填写实际放置本站友链的页面,提交后将在后台检测该页面

)}
{logoPreview ? ( ) : ( 预览 )}
setLogo(e.target.value)} placeholder="LOGO 图片地址" maxLength={512} /> uploadLogo(e.target.files?.[0])} />

提交后立即返回,回链检测在后台进行,结果供管理员参考

); }