import { useState, useEffect } from 'react'; import { useRouter } from 'next/router'; import Head from 'next/head'; import DashboardLayout from '../../components/Layout/DashboardLayout'; import { toast } from 'react-hot-toast'; import { UserIcon, MagnifyingGlassIcon, PlusIcon, EyeIcon, PencilIcon, TrashIcon, StarIcon, LanguageIcon, ClockIcon, CheckCircleIcon, XCircleIcon, ExclamationTriangleIcon, ArrowDownTrayIcon, UserPlusIcon, PhoneIcon, EnvelopeIcon, MapPinIcon, CalendarIcon, CurrencyDollarIcon, AcademicCapIcon, XMarkIcon } from '@heroicons/react/24/outline'; import { getDemoData } from '../../lib/demo-data'; import { formatTime } from '../../lib/utils'; interface Interpreter { id: string; name: string; email: string; phone: string; avatar?: string; languages: string[]; specialties: string[]; experience_years: number; rating: number; total_calls: number; total_hours: number; hourly_rate: number; status: 'active' | 'inactive' | 'busy' | 'offline'; location: string; certifications: string[]; bio: string; joined_at: string; last_active: string; availability: 'available' | 'busy' | 'offline'; } interface InterpreterFilters { search: string; status: string; language: string; rating: string; availability: string; } export default function Interpreters() { const router = useRouter(); const [interpreters, setInterpreters] = useState([]); const [loading, setLoading] = useState(true); const [selectedInterpreters, setSelectedInterpreters] = useState([]); const [currentPage, setCurrentPage] = useState(1); const [totalPages, setTotalPages] = useState(1); const [totalCount, setTotalCount] = useState(0); const [filters, setFilters] = useState({ search: '', status: '', language: '', rating: '', availability: '' }); // 添加模态框状态 const [showAddInterpreterModal, setShowAddInterpreterModal] = useState(false); const [newInterpreter, setNewInterpreter] = useState({ name: '', email: '', phone: '', languages: '', specialties: '', experience_years: 0, hourly_rate: 0, location: '', bio: '', status: 'active' as 'active' | 'inactive' | 'busy' | 'offline', availability: 'available' as 'available' | 'busy' | 'offline' }); const [isSubmitting, setIsSubmitting] = useState(false); const pageSize = 10; useEffect(() => { fetchInterpreters(); }, [currentPage, filters]); const fetchInterpreters = async () => { try { setLoading(true); // 模拟加载延迟 await new Promise(resolve => setTimeout(resolve, 800)); // 使用演示数据 const mockInterpreters: Interpreter[] = [ { id: '1', name: '王翻译', email: 'wang@example.com', phone: '+86 138-0000-0001', avatar: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80', languages: ['中文', '英文', '日文'], specialties: ['商务翻译', '法律翻译', '技术翻译'], experience_years: 8, rating: 4.9, total_calls: 1250, total_hours: 3200, hourly_rate: 150, status: 'active', location: '北京', certifications: ['CATTI二级', '商务英语高级', 'JLPT N1'], bio: '资深翻译员,专注于商务和法律翻译,拥有丰富的国际会议翻译经验。', joined_at: '2020-03-15T10:00:00Z', last_active: '2024-01-20T15:30:00Z', availability: 'available' }, { id: '2', name: '李专家', email: 'li@example.com', phone: '+86 138-0000-0002', avatar: 'https://images.unsplash.com/photo-1494790108755-2616b612b786?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80', languages: ['中文', '韩文', '英文'], specialties: ['医学翻译', '学术翻译'], experience_years: 12, rating: 4.8, total_calls: 980, total_hours: 2800, hourly_rate: 180, status: 'active', location: '上海', certifications: ['医学翻译资格证', 'TOPIK 6级'], bio: '医学翻译专家,在医疗器械和药物研发领域有深厚的专业背景。', joined_at: '2019-08-20T10:00:00Z', last_active: '2024-01-20T14:15:00Z', availability: 'busy' }, { id: '3', name: '张语言', email: 'zhang@example.com', phone: '+86 138-0000-0003', avatar: 'https://images.unsplash.com/photo-1519244703995-f4e0f30006d5?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80', languages: ['中文', '德文', '法文'], specialties: ['文学翻译', '艺术翻译'], experience_years: 6, rating: 4.7, total_calls: 650, total_hours: 1800, hourly_rate: 120, status: 'active', location: '广州', certifications: ['德语C2证书', '法语DALF C1'], bio: '擅长文学和艺术类翻译,对欧洲文化有深入了解。', joined_at: '2021-05-10T10:00:00Z', last_active: '2024-01-19T16:45:00Z', availability: 'available' }, { id: '4', name: '陈口译', email: 'chen@example.com', phone: '+86 138-0000-0004', languages: ['中文', '西班牙文', '葡萄牙文'], specialties: ['旅游翻译', '贸易翻译'], experience_years: 4, rating: 4.5, total_calls: 420, total_hours: 1200, hourly_rate: 100, status: 'inactive', location: '深圳', certifications: ['DELE B2', '葡语中级证书'], bio: '专注于拉美地区的商务和旅游翻译服务。', joined_at: '2022-01-15T10:00:00Z', last_active: '2024-01-18T09:30:00Z', availability: 'offline' }, { id: '5', name: '刘同传', email: 'liu@example.com', phone: '+86 138-0000-0005', avatar: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80', languages: ['中文', '英文', '俄文'], specialties: ['同声传译', '会议翻译'], experience_years: 15, rating: 5.0, total_calls: 1800, total_hours: 4500, hourly_rate: 250, status: 'active', location: '北京', certifications: ['同声传译资格证', '俄语专业八级'], bio: '顶级同声传译员,曾为多个国际会议提供翻译服务。', joined_at: '2018-12-01T10:00:00Z', last_active: '2024-01-20T16:00:00Z', availability: 'available' }, { id: '6', name: '赵技术', email: 'zhao@example.com', phone: '+86 138-0000-0006', languages: ['中文', '英文'], specialties: ['IT翻译', '软件本地化'], experience_years: 5, rating: 4.6, total_calls: 320, total_hours: 900, hourly_rate: 130, status: 'active', location: '杭州', certifications: ['计算机技术翻译证书'], bio: '专业IT翻译,熟悉各种编程语言和技术文档翻译。', joined_at: '2021-09-01T10:00:00Z', last_active: '2024-01-20T11:20:00Z', availability: 'busy' } ]; // 应用过滤器 let filteredInterpreters = mockInterpreters; if (filters.search) { filteredInterpreters = filteredInterpreters.filter(interpreter => interpreter.name.toLowerCase().includes(filters.search.toLowerCase()) || interpreter.email.toLowerCase().includes(filters.search.toLowerCase()) || interpreter.languages.some(lang => lang.toLowerCase().includes(filters.search.toLowerCase())) || interpreter.specialties.some(spec => spec.toLowerCase().includes(filters.search.toLowerCase())) ); } if (filters.status) { filteredInterpreters = filteredInterpreters.filter(interpreter => interpreter.status === filters.status); } if (filters.language) { filteredInterpreters = filteredInterpreters.filter(interpreter => interpreter.languages.some(lang => lang.toLowerCase().includes(filters.language.toLowerCase())) ); } if (filters.rating) { const minRating = parseFloat(filters.rating); filteredInterpreters = filteredInterpreters.filter(interpreter => interpreter.rating >= minRating); } if (filters.availability) { filteredInterpreters = filteredInterpreters.filter(interpreter => interpreter.availability === filters.availability); } // 分页 const startIndex = (currentPage - 1) * pageSize; const endIndex = startIndex + pageSize; const paginatedInterpreters = filteredInterpreters.slice(startIndex, endIndex); setInterpreters(paginatedInterpreters); setTotalCount(filteredInterpreters.length); setTotalPages(Math.ceil(filteredInterpreters.length / pageSize)); } catch (error) { console.error('Failed to fetch interpreters:', error); toast.error('加载翻译员失败'); } finally { setLoading(false); } }; const handleSearch = (value: string) => { setFilters(prev => ({ ...prev, search: value })); setCurrentPage(1); }; const handleFilterChange = (key: keyof InterpreterFilters, value: string) => { setFilters(prev => ({ ...prev, [key]: value })); setCurrentPage(1); }; const handleSelectInterpreter = (interpreterId: string) => { setSelectedInterpreters(prev => prev.includes(interpreterId) ? prev.filter(id => id !== interpreterId) : [...prev, interpreterId] ); }; const handleSelectAll = () => { if (selectedInterpreters.length === interpreters.length) { setSelectedInterpreters([]); } else { setSelectedInterpreters(interpreters.map(interpreter => interpreter.id)); } }; const handleBulkAction = async (action: 'activate' | 'deactivate' | 'delete') => { if (selectedInterpreters.length === 0) { toast.error('请选择要操作的翻译员'); return; } try { const actionText = action === 'activate' ? '激活' : action === 'deactivate' ? '停用' : '删除'; toast.loading(`正在${actionText}翻译员...`, { id: 'bulk-action' }); // 模拟操作延迟 await new Promise(resolve => setTimeout(resolve, 1500)); toast.success(`成功${actionText} ${selectedInterpreters.length} 个翻译员`, { id: 'bulk-action' }); setSelectedInterpreters([]); fetchInterpreters(); } catch (error) { toast.error('操作失败', { id: 'bulk-action' }); } }; const handleExport = async () => { try { toast.loading('正在导出翻译员数据...', { id: 'export' }); // 模拟导出延迟 await new Promise(resolve => setTimeout(resolve, 2000)); toast.success('翻译员数据导出成功', { id: 'export' }); } catch (error) { toast.error('导出失败', { id: 'export' }); } }; const getStatusColor = (status: string) => { switch (status) { case 'active': return 'text-green-800 bg-green-100'; case 'inactive': return 'text-gray-800 bg-gray-100'; case 'busy': return 'text-yellow-800 bg-yellow-100'; case 'offline': return 'text-red-800 bg-red-100'; default: return 'text-gray-800 bg-gray-100'; } }; const getStatusText = (status: string) => { switch (status) { case 'active': return '活跃'; case 'inactive': return '不活跃'; case 'busy': return '忙碌'; case 'offline': return '离线'; default: return status; } }; const getAvailabilityColor = (availability: string) => { switch (availability) { case 'available': return 'text-green-600'; case 'busy': return 'text-yellow-600'; case 'offline': return 'text-red-600'; default: return 'text-gray-600'; } }; const getAvailabilityText = (availability: string) => { switch (availability) { case 'available': return '可接单'; case 'busy': return '忙碌中'; case 'offline': return '离线'; default: return availability; } }; const renderStars = (rating: number) => { return (
{[...Array(5)].map((_, i) => ( ))} {rating.toFixed(1)}
); }; // 添加翻译员提交函数 const handleAddInterpreter = async (e: React.FormEvent) => { e.preventDefault(); setIsSubmitting(true); try { // 模拟API调用 await new Promise(resolve => setTimeout(resolve, 1000)); // 创建新翻译员对象 const newInterpreterData: Interpreter = { id: Date.now().toString(), ...newInterpreter, languages: newInterpreter.languages.split(',').map(lang => lang.trim()), specialties: newInterpreter.specialties.split(',').map(spec => spec.trim()), rating: 5.0, total_calls: 0, total_hours: 0, certifications: [], joined_at: new Date().toISOString(), last_active: new Date().toISOString() }; // 添加到翻译员列表 setInterpreters(prev => [newInterpreterData, ...prev]); // 重置表单 setNewInterpreter({ name: '', email: '', phone: '', languages: '', specialties: '', experience_years: 0, hourly_rate: 0, location: '', bio: '', status: 'active', availability: 'available' }); // 关闭模态框 setShowAddInterpreterModal(false); // 可以添加成功提示 alert('翻译员添加成功!'); } catch (error) { console.error('添加翻译员失败:', error); alert('添加翻译员失败,请重试'); } finally { setIsSubmitting(false); } }; // 添加翻译员模态框组件 const AddInterpreterModal = () => (

添加新翻译员

setNewInterpreter({...newInterpreter, name: e.target.value})} />
setNewInterpreter({...newInterpreter, email: e.target.value})} />
setNewInterpreter({...newInterpreter, phone: e.target.value})} />
setNewInterpreter({...newInterpreter, location: e.target.value})} />
setNewInterpreter({...newInterpreter, languages: e.target.value})} />
setNewInterpreter({...newInterpreter, specialties: e.target.value})} />
setNewInterpreter({...newInterpreter, experience_years: parseInt(e.target.value) || 0})} />
setNewInterpreter({...newInterpreter, hourly_rate: parseFloat(e.target.value) || 0})} />