'use client'; import { useState, useEffect, useCallback } from 'react'; import Link from 'next/link'; import { useSearchParams } from 'next/navigation'; import { Plus, Search, Edit, Trash2, FileText, Loader2 } from 'lucide-react'; interface ContentItem { id: string; type: 'news' | 'product' | 'service' | 'case'; title: string; slug: string; excerpt: string | null; status: 'draft' | 'published' | 'archived'; category: string | null; createdAt: string; publishedAt: string | null; } interface Pagination { page: number; limit: number; total: number; totalPages: number; } const typeLabels: Record = { news: '新闻', product: '产品', service: '服务', case: '案例', }; const statusLabels: Record = { draft: '草稿', published: '已发布', archived: '已归档', }; const statusColors: Record = { draft: 'bg-yellow-100 text-yellow-800', published: 'bg-green-100 text-green-800', archived: 'bg-gray-100 text-gray-800', }; export default function ContentListPage() { const searchParams = useSearchParams(); const [items, setItems] = useState([]); const [pagination, setPagination] = useState({ page: 1, limit: 20, total: 0, totalPages: 0, }); const [loading, setLoading] = useState(true); const [search, setSearch] = useState(searchParams.get('search') || ''); const [typeFilter, setTypeFilter] = useState(searchParams.get('type') || ''); const [statusFilter, setStatusFilter] = useState(searchParams.get('status') || ''); const [deleteId, setDeleteId] = useState(null); const [deleting, setDeleting] = useState(false); const fetchContent = useCallback(async () => { setLoading(true); try { const params = new URLSearchParams(); params.set('page', pagination.page.toString()); params.set('limit', pagination.limit.toString()); if (search) params.set('search', search); if (typeFilter) params.set('type', typeFilter); if (statusFilter) params.set('status', statusFilter); const res = await fetch(`/api/admin/content?${params}`); const data = await res.json(); if (res.ok) { setItems(data.items); setPagination(data.pagination); } } catch (error) { console.error('获取内容列表失败:', error); } finally { setLoading(false); } }, [pagination.page, pagination.limit, search, typeFilter, statusFilter]); useEffect(() => { fetchContent(); }, [fetchContent]); const handleSearch = (e: React.FormEvent) => { e.preventDefault(); setPagination(prev => ({ ...prev, page: 1 })); fetchContent(); }; const handleDelete = async () => { if (!deleteId) return; setDeleting(true); try { const res = await fetch(`/api/admin/content/${deleteId}`, { method: 'DELETE', }); if (res.ok) { setItems(items.filter(item => item.id !== deleteId)); setDeleteId(null); } } catch (error) { console.error('删除失败:', error); } finally { setDeleting(false); } }; const formatDate = (dateStr: string) => { return new Date(dateStr).toLocaleDateString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', }); }; return (

内容管理

新建内容
setSearch(e.target.value)} placeholder="搜索标题..." className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#C41E3A] focus:border-transparent outline-none" />
{loading ? (
) : items.length === 0 ? (

暂无内容

创建第一个内容
) : ( <>
{items.map((item) => ( ))}
标题 类型 状态 分类 创建时间 操作

{item.title}

{item.slug}

{typeLabels[item.type]} {statusLabels[item.status]} {item.category || '-'} {formatDate(item.createdAt)}
{pagination.totalPages > 1 && (

共 {pagination.total} 条记录

)} )}
{deleteId && (

确认删除

确定要删除此内容吗?此操作不可撤销。

)}
); }