"use client"; import { useState, useEffect } from "react"; import { useRouter } from "next/navigation"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent } from "@/components/ui/dialog"; import { ArrowLeft, Download, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, Edit, Scissors, Sparkles } from "lucide-react"; import { Input } from "@/components/ui/input"; import Image from "next/image"; import { toast } from "sonner"; type GalleryImage = { id: string; messageId: string; url: string; // 原图 URL thumbnailUrl?: string; // 缩略图 URL(可选,兼容旧数据) alt: string; imageSize?: string; // 图片尺寸(如 "2K", "4K") createdAt: string; chatId: string; }; type Pagination = { page: number; pageSize: number; total: number; totalPages: number; }; export default function GalleryPage() { const router = useRouter(); const [images, setImages] = useState([]); const [loading, setLoading] = useState(true); const [pagination, setPagination] = useState({ page: 1, pageSize: 24, total: 0, totalPages: 0, }); const [selectedImage, setSelectedImage] = useState(null); const [dialogOpen, setDialogOpen] = useState(false); const [pageInput, setPageInput] = useState(""); const [processingImageId, setProcessingImageId] = useState(null); const [enhancingImageId, setEnhancingImageId] = useState(null); const fetchImages = async (page: number) => { setLoading(true); try { const res = await fetch(`/api/gallery?page=${page}&pageSize=24`); const data = await res.json(); if (data.images) { setImages(data.images); setPagination(data.pagination); } } catch (error) { console.error("Failed to fetch images:", error); } finally { setLoading(false); } }; useEffect(() => { fetchImages(1); }, []); const handleImageClick = (image: GalleryImage) => { setSelectedImage(image); setDialogOpen(true); }; const handleDownload = async (url: string, alt: string) => { try { const response = await fetch(url); const blob = await response.blob(); const blobUrl = window.URL.createObjectURL(blob); const link = document.createElement("a"); link.href = blobUrl; link.download = `${alt || "image"}-${Date.now()}.png`; document.body.appendChild(link); link.click(); document.body.removeChild(link); window.URL.revokeObjectURL(blobUrl); } catch (error) { console.error("Download failed:", error); } }; const handleEdit = (imageUrl: string) => { // 跳转到首页,并将图片URL作为参数传递 router.push(`/?editImage=${encodeURIComponent(imageUrl)}`); }; const handleRemoveBackground = async (image: GalleryImage, e: React.MouseEvent) => { e.stopPropagation(); // 阻止触发图片点击事件 if (processingImageId === image.id) return; // 防止重复点击 setProcessingImageId(image.id); try { toast.info("正在处理抠图,请稍候..."); // 获取原图并转换为Base64 const response = await fetch(image.url); const blob = await response.blob(); const reader = new FileReader(); reader.onloadend = async () => { try { const base64Data = (reader.result as string).split(",")[1]; // 调用抠图API const rmbgResponse = await fetch("/api/rmbg", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ image_base64: base64Data, prompt: `抠图处理 - ${image.alt}`, chatId: image.chatId, messageId: image.messageId, }), }); if (!rmbgResponse.ok) { const error = await rmbgResponse.json(); throw new Error(error.error || error.detail || "抠图失败"); } const result = await rmbgResponse.json(); // 刷新相册列表以显示新图片 await fetchImages(pagination.page); toast.success(`抠图完成!处理时间: ${result.processing_time?.toFixed(2) || "未知"}秒`); } catch (error) { console.error("[抠图] 错误:", error); toast.error(error instanceof Error ? error.message : "抠图处理失败"); } finally { setProcessingImageId(null); } }; reader.onerror = () => { toast.error("图片读取失败"); setProcessingImageId(null); }; reader.readAsDataURL(blob); } catch (error) { console.error("[抠图] 错误:", error); toast.error(error instanceof Error ? error.message : "抠图处理失败"); setProcessingImageId(null); } }; const goToPage = (page: number) => { if (page >= 1 && page <= pagination.totalPages) { fetchImages(page); setPageInput(""); // 清空输入框 } }; const handlePageInputSubmit = () => { const pageNum = Number.parseInt(pageInput); if (!Number.isNaN(pageNum) && pageNum >= 1 && pageNum <= pagination.totalPages) { goToPage(pageNum); } }; return (

我的图册

共 {pagination.total} 张AI生成的图片

{loading ? (
加载中...
) : images.length === 0 ? (
暂无生图记录,快去生成一些图片吧!
) : ( <>
{images.map((img) => (
handleImageClick(img)} >
{img.alt}
{/* 🆕 操作按钮(悬停时显示) */}

{img.alt}

{new Date(img.createdAt).toLocaleString("zh-CN", { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" })} • AI生成

))}
{/* 分页信息 */}
{/* 始终显示页码信息 */}
第 {pagination.page} 页 / 共 {pagination.totalPages} 页
{/* 只有多页时才显示翻页按钮 */} {pagination.totalPages > 1 && (
{/* 左侧:第一页按钮 */} {/* 上一页 */} {/* 页码按钮 */}
{Array.from({ length: pagination.totalPages }, (_, i) => i + 1) .filter((p) => { // 显示当前页前后1页 return ( p === 1 || p === pagination.totalPages || Math.abs(p - pagination.page) <= 1 ); }) .map((p, idx, arr) => { // 添加省略号 const showEllipsis = idx > 0 && p - arr[idx - 1] > 1; return (
{showEllipsis && ( ... )}
); })}
{/* 下一页 */} {/* 右侧:最后一页按钮 */} {/* 页码输入跳转 */}
跳至 setPageInput(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") { handlePageInputSubmit(); } }} className="w-16 h-8 text-center" placeholder={String(pagination.page)} /> 页
)}
)} {/* 图片预览对话框 */} {selectedImage && (
{selectedImage.alt}

{selectedImage.alt}

{new Date(selectedImage.createdAt).toLocaleString("zh-CN")}

)}
); }