/** * V10 · Sprint 3 · ShareDialog * * 分享弹窗:QR Code + 链接 + 复制 + 海报生成入口 * V10 不变量:移动端 48px 触发区 */ import { useState } from 'react'; import { QRCodeSVG } from 'qrcode.react'; import { X, Copy, Check, Share2 } from 'lucide-react'; import { useShareLinkCreate, useShareLinkDelete, useShareLinkStatsQuery } from '@/hooks/useShareLink'; import { usePosterGenerateMutation } from '@/hooks/usePosterGenerate'; interface Props { planId: string; planTitle: string; open: boolean; onClose: () => void; } export function ShareDialog({ planId, planTitle, open, onClose }: Props) { const [copied, setCopied] = useState(false); const create = useShareLinkCreate(); const del = useShareLinkDelete(); const posterGen = usePosterGenerateMutation(); const code = create.data?.code ?? null; const stats = useShareLinkStatsQuery(code); if (!open) return null; const handleCreate = (): void => { create.mutate({ planId, expiresIn: 30 }); }; const handleCopy = (): void => { if (!create.data?.url) return; void navigator.clipboard .writeText(create.data.url) .then(() => { setCopied(true); setTimeout(() => setCopied(false), 2000); }) .catch(() => { // 剪贴板不可用 }); }; const handleDelete = (): void => { if (!create.data?.id) return; del.mutate(create.data.id, { onSuccess: () => create.reset(), }); }; const handleGeneratePoster = (): void => { posterGen.mutate({ planId, template: 'classic' }); }; return (
{planTitle}
{!create.data ? (访问数
{stats.data.views}
独立访客
{stats.data.uniqueVisitors}
最近访问
{stats.data.lastAccessedAt ? new Date(stats.data.lastAccessedAt).toLocaleDateString() : '—'}
撤销失败,请稍后重试。
)}