import { useState, useEffect } from 'react'; import { useRouter } from 'next/router'; import Head from 'next/head'; import { toast } from 'react-hot-toast'; import { MagnifyingGlassIcon, DocumentTextIcon, CloudArrowUpIcon, CloudArrowDownIcon, EyeIcon, TrashIcon, PencilIcon, CheckCircleIcon, ClockIcon, ExclamationCircleIcon, ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/24/outline'; import { supabase, TABLES } from '@/lib/supabase'; import { getDemoData } from '@/lib/demo-data'; import { formatTime } from '@/utils'; import Layout from '@/components/Layout'; interface Document { id: string; user_id: string; original_name: string; file_size: number; file_type: string; source_language: string; target_language: string; status: 'pending' | 'processing' | 'completed' | 'failed'; progress: number; translated_url?: string; cost: number; created_at: string; updated_at: string; user_name?: string; } interface DocumentFilters { search: string; status: 'all' | 'pending' | 'processing' | 'completed' | 'failed'; language: string; fileType: string; sortBy: 'created_at' | 'file_size' | 'cost' | 'progress'; sortOrder: 'asc' | 'desc'; } export default function DocumentsPage() { const [documents, setDocuments] = useState([]); const [loading, setLoading] = useState(true); const [currentPage, setCurrentPage] = useState(1); const [totalPages, setTotalPages] = useState(1); const [totalCount, setTotalCount] = useState(0); const [isDemoMode, setIsDemoMode] = useState(false); const [filters, setFilters] = useState({ search: '', status: 'all', language: 'all', fileType: 'all', sortBy: 'created_at', sortOrder: 'desc' }); const router = useRouter(); const pageSize = 20; // 获取文档数据 const fetchDocuments = async (page = 1) => { try { setLoading(true); // 检查是否为演示模式 const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL; const isDemo = !supabaseUrl || supabaseUrl === 'https://demo.supabase.co' || supabaseUrl === ''; setIsDemoMode(isDemo); if (isDemo) { // 使用演示数据 const result = await getDemoData.documents(); setDocuments(result); setTotalCount(result.length); setTotalPages(Math.ceil(result.length / pageSize)); setCurrentPage(page); } else { // 使用真实数据 - 这里需要根据实际数据库结构调整 // 暂时使用演示数据 const result = await getDemoData.documents(); setDocuments(result); setTotalCount(result.length); setTotalPages(Math.ceil(result.length / pageSize)); setCurrentPage(page); } } catch (error) { console.error('Error fetching documents:', error); toast.error('获取文档列表失败'); } finally { setLoading(false); } }; // 处理筛选变更 const handleFilterChange = (key: keyof DocumentFilters, value: any) => { setFilters(prev => ({ ...prev, [key]: value })); }; // 应用筛选 const applyFilters = () => { setCurrentPage(1); fetchDocuments(1); }; // 重置筛选 const resetFilters = () => { setFilters({ search: '', status: 'all', language: 'all', fileType: 'all', sortBy: 'created_at', sortOrder: 'desc' }); setCurrentPage(1); fetchDocuments(1); }; // 获取状态颜色 const getStatusColor = (status: string) => { switch (status) { case 'completed': return 'bg-green-100 text-green-800'; case 'processing': return 'bg-blue-100 text-blue-800'; case 'pending': return 'bg-yellow-100 text-yellow-800'; case 'failed': return 'bg-red-100 text-red-800'; default: return 'bg-gray-100 text-gray-800'; } }; // 获取状态文本 const getStatusText = (status: string) => { switch (status) { case 'completed': return '已完成'; case 'processing': return '处理中'; case 'pending': return '等待中'; case 'failed': return '失败'; default: return '未知'; } }; // 获取状态图标 const getStatusIcon = (status: string) => { switch (status) { case 'completed': return ; case 'processing': return ; case 'pending': return ; case 'failed': return ; default: return ; } }; // 格式化文件大小 const formatFileSize = (bytes: number) => { if (bytes === 0) return '0 Bytes'; const k = 1024; const sizes = ['Bytes', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; }; // 删除文档 const handleDeleteDocument = async (documentId: string) => { if (confirm('确定要删除此文档吗?')) { try { // 这里应该调用删除API toast.success('文档删除成功'); fetchDocuments(); } catch (error) { toast.error('删除文档失败'); } } }; // 下载文档 const handleDownloadDocument = async (document: Document) => { try { // 这里应该调用下载API toast.success('开始下载文档'); } catch (error) { toast.error('下载文档失败'); } }; useEffect(() => { fetchDocuments(); }, []); return ( 文档管理 - 口译服务管理后台
{/* 页面标题 */}

文档管理

{/* 搜索和筛选 */}
{/* 搜索框 */}
handleFilterChange('search', e.target.value)} className="block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md leading-5 bg-white placeholder-gray-500 focus:outline-none focus:placeholder-gray-400 focus:ring-1 focus:ring-blue-500 focus:border-blue-500" />
{/* 状态筛选 */}
{/* 语言筛选 */}
{/* 文件类型筛选 */}
{/* 文档列表 */} {loading ? (
) : (

文档列表 ({totalCount} 个文档)

{documents.map((document) => (

{document.original_name}

{document.user_name} | {formatFileSize(document.file_size)} | {document.file_type.toUpperCase()}

{document.source_language} → {document.target_language} | ¥{document.cost.toFixed(2)}

{/* 进度条 */} {document.status === 'processing' && (

{document.progress}%

)} {/* 状态 */}
{getStatusIcon(document.status)} {getStatusText(document.status)}
{/* 操作按钮 */}
{document.status === 'completed' && document.translated_url && ( )}
{/* 时间信息 */}
创建时间: {formatTime(document.created_at)} | 更新时间: {formatTime(document.updated_at)}
))} {documents.length === 0 && (

暂无文档

开始上传您的第一个文档

)}
{/* 分页 */} {totalPages > 1 && (

显示第 {(currentPage - 1) * pageSize + 1} 到{' '} {Math.min(currentPage * pageSize, totalCount)} {' '} 个,共 {totalCount} 个文档

)}
)}
); }