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 { PhoneIcon, MagnifyingGlassIcon, PlayIcon, StopIcon, PauseIcon, DocumentTextIcon, CalendarIcon, ClockIcon, UserIcon, LanguageIcon, SpeakerWaveIcon, ArrowDownTrayIcon, FunnelIcon, EyeIcon, CheckCircleIcon, XCircleIcon, ExclamationTriangleIcon } from '@heroicons/react/24/outline'; import { getDemoData } from '../../lib/demo-data'; import { formatTime } from '../../lib/utils'; interface CallRecord { id: string; user_name: string; interpreter_name: string; language_pair: string; start_time: string; end_time: string; duration: number; status: 'active' | 'completed' | 'failed' | 'cancelled'; call_type: 'audio' | 'video'; recording_url?: string; cost: number; notes?: string; } interface CallFilters { search: string; status: string; language: string; date_range: string; call_type: string; } export default function CallRecords() { const router = useRouter(); const [calls, setCalls] = useState([]); const [loading, setLoading] = useState(true); const [selectedCalls, setSelectedCalls] = useState([]); const [currentPage, setCurrentPage] = useState(1); const [totalPages, setTotalPages] = useState(1); const [totalCount, setTotalCount] = useState(0); const [filters, setFilters] = useState({ search: '', status: '', language: '', date_range: '', call_type: '' }); const pageSize = 10; useEffect(() => { fetchCalls(); }, [currentPage, filters]); const fetchCalls = async () => { try { setLoading(true); // 模拟加载延迟 await new Promise(resolve => setTimeout(resolve, 800)); // 使用演示数据 const mockCalls: CallRecord[] = [ { id: '1', user_name: '张三', interpreter_name: '王五', language_pair: '中文-英文', start_time: '2024-01-20T14:30:00Z', end_time: '2024-01-20T15:15:00Z', duration: 2700, // 45分钟 status: 'completed', call_type: 'video', recording_url: 'https://example.com/recording1.mp4', cost: 180, notes: '商务会议翻译,客户满意度高' }, { id: '2', user_name: '李四', interpreter_name: '赵六', language_pair: '中文-日文', start_time: '2024-01-20T10:00:00Z', end_time: '2024-01-20T10:30:00Z', duration: 1800, // 30分钟 status: 'completed', call_type: 'audio', recording_url: 'https://example.com/recording2.mp3', cost: 120, notes: '技术文档翻译' }, { id: '3', user_name: '王二', interpreter_name: '孙七', language_pair: '中文-韩文', start_time: '2024-01-20T16:00:00Z', end_time: '', duration: 0, status: 'active', call_type: 'video', cost: 0, notes: '正在进行中的通话' }, { id: '4', user_name: '陈五', interpreter_name: '周八', language_pair: '中文-法文', start_time: '2024-01-19T09:30:00Z', end_time: '2024-01-19T09:35:00Z', duration: 300, // 5分钟 status: 'failed', call_type: 'audio', cost: 0, notes: '连接失败,技术问题' }, { id: '5', user_name: '刘六', interpreter_name: '吴九', language_pair: '中文-德文', start_time: '2024-01-19T14:00:00Z', end_time: '2024-01-19T14:05:00Z', duration: 300, // 5分钟 status: 'cancelled', call_type: 'video', cost: 0, notes: '用户取消通话' }, { id: '6', user_name: '黄七', interpreter_name: '郑十', language_pair: '中文-西班牙文', start_time: '2024-01-18T11:00:00Z', end_time: '2024-01-18T12:30:00Z', duration: 5400, // 90分钟 status: 'completed', call_type: 'video', recording_url: 'https://example.com/recording3.mp4', cost: 360, notes: '法律合同翻译,专业性强' } ]; // 应用过滤器 let filteredCalls = mockCalls; if (filters.search) { filteredCalls = filteredCalls.filter(call => call.user_name.toLowerCase().includes(filters.search.toLowerCase()) || call.interpreter_name.toLowerCase().includes(filters.search.toLowerCase()) || call.language_pair.toLowerCase().includes(filters.search.toLowerCase()) ); } if (filters.status) { filteredCalls = filteredCalls.filter(call => call.status === filters.status); } if (filters.language) { filteredCalls = filteredCalls.filter(call => call.language_pair.toLowerCase().includes(filters.language.toLowerCase()) ); } if (filters.call_type) { filteredCalls = filteredCalls.filter(call => call.call_type === filters.call_type); } // 分页 const startIndex = (currentPage - 1) * pageSize; const endIndex = startIndex + pageSize; const paginatedCalls = filteredCalls.slice(startIndex, endIndex); setCalls(paginatedCalls); setTotalCount(filteredCalls.length); setTotalPages(Math.ceil(filteredCalls.length / pageSize)); } catch (error) { console.error('Failed to fetch calls:', error); toast.error('加载通话记录失败'); } finally { setLoading(false); } }; const handleSearch = (value: string) => { setFilters(prev => ({ ...prev, search: value })); setCurrentPage(1); }; const handleFilterChange = (key: keyof CallFilters, value: string) => { setFilters(prev => ({ ...prev, [key]: value })); setCurrentPage(1); }; const handleSelectCall = (callId: string) => { setSelectedCalls(prev => prev.includes(callId) ? prev.filter(id => id !== callId) : [...prev, callId] ); }; const handleSelectAll = () => { if (selectedCalls.length === calls.length) { setSelectedCalls([]); } else { setSelectedCalls(calls.map(call => call.id)); } }; 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 handlePlayRecording = (recordingUrl: string) => { if (recordingUrl) { toast.success('开始播放录音'); // 这里可以集成音频播放器 } else { toast.error('录音文件不存在'); } }; const getStatusColor = (status: string) => { switch (status) { case 'completed': return 'text-green-800 bg-green-100'; case 'active': return 'text-blue-800 bg-blue-100'; case 'failed': return 'text-red-800 bg-red-100'; case 'cancelled': return 'text-gray-800 bg-gray-100'; default: return 'text-gray-800 bg-gray-100'; } }; const getStatusText = (status: string) => { switch (status) { case 'completed': return '已完成'; case 'active': return '进行中'; case 'failed': return '失败'; case 'cancelled': return '已取消'; default: return status; } }; const getStatusIcon = (status: string) => { switch (status) { case 'completed': return ; case 'active': return ; case 'failed': return ; case 'cancelled': return ; default: return ; } }; const formatDuration = (seconds: number) => { if (seconds === 0) return '-'; const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); const remainingSeconds = seconds % 60; if (hours > 0) { return `${hours}:${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`; } else { return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`; } }; return ( <> 通话记录 - 翻译服务管理系统
{/* 页面标题和操作 */}

通话记录

查看和管理所有的翻译通话记录,包括录音文件和通话详情。

{/* 搜索和过滤器 */}
handleSearch(e.target.value)} />
handleFilterChange('language', e.target.value)} />
{/* 通话记录列表 */}
{loading ? (
) : ( <>
{calls.map((call) => ( ))}
0} onChange={handleSelectAll} /> 通话信息 参与者 语言对 时长/费用 状态 录音 操作
handleSelectCall(call.id)} />
{call.call_type === 'video' ? '视频通话' : '音频通话'}
{formatTime(call.start_time)}
{call.user_name}
{call.interpreter_name}
{call.language_pair}
{formatDuration(call.duration)}
¥{call.cost}
{getStatusIcon(call.status)} {getStatusText(call.status)}
{call.recording_url ? ( ) : ( 无录音 )}
{/* 分页 */} {totalPages > 1 && (

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

)} )}
); }