"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, Sparkles, User, Building2, Clock, Bot } from "lucide-react"; import { Input } from "@/components/ui/input"; import Image from "next/image"; type FeaturedImage = { id: string; thumbnailUrl: string; originalUrl: string; imageSize: string; prompt: string; modelId: string; modelName: string; createdAt: string; featuredAt: string; user: { id: string; name: string; department: string; }; }; type Pagination = { page: number; pageSize: number; total: number; totalPages: number; }; export default function FeaturedPage() { 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 fetchImages = async (page: number) => { setLoading(true); try { const res = await fetch(`/api/featured?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 featured images:", error); } finally { setLoading(false); } }; useEffect(() => { fetchImages(1); }, []); const handleImageClick = (image: FeaturedImage) => { setSelectedImage(image); setDialogOpen(true); }; const handleDownload = async (url: string, prompt: 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 = `featured-${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 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 (

AI智能精选

共 {pagination.total} 张优秀AI作品

{loading ? (
加载中...
) : images.length === 0 ? (

暂无精选作品

管理员可以在后台标记优秀作品

) : ( <>
{images.map((img) => (
handleImageClick(img)} > {/* 精选图标 */}
精选
{img.prompt
{/* 底部信息区域 */}
{/* 用户信息 */}

{img.user.name}

{img.user.department}

{/* 提示词 */}

{img.prompt || "无提示词"}

{/* 底部元信息 */}
{img.modelName} {new Date(img.createdAt).toLocaleDateString("zh-CN", { month: "short", day: "numeric", })}
))}
{/* 分页 */}
第 {pagination.page} 页 / 共 {pagination.totalPages} 页
{pagination.totalPages > 1 && (
{Array.from({ length: pagination.totalPages }, (_, i) => i + 1) .filter((p) => { 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) => e.key === "Enter" && handlePageInputSubmit()} placeholder="跳转" className="w-20 h-8 text-sm" />
)}
)} {/* 图片预览对话框 */} {selectedImage && (
{/* 图片 */}
{selectedImage.prompt {/* 精选标记 */}
精选作品
{/* 信息区域 */}

{selectedImage.user.name}

{selectedImage.user.department}

生成时间

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

提示词

{selectedImage.prompt || "无提示词"}

{selectedImage.modelName} 尺寸: {selectedImage.imageSize || "2K"}
)}
); }