import * as React from 'react'; import { useState, useEffect } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import { Card, Descriptions, Button, Tag, Typography, Space, Modal, Input, message, Spin, Calendar, Badge, Avatar, Timeline, Tabs, Form, DatePicker, Select, Divider, } from 'antd'; import { ArrowLeftOutlined, CalendarOutlined, ClockCircleOutlined, UserOutlined, PhoneOutlined, VideoCameraOutlined, EditOutlined, DeleteOutlined, CheckCircleOutlined, ExclamationCircleOutlined, MessageOutlined, LinkOutlined, DollarOutlined, TranslationOutlined, } from '@ant-design/icons'; import { Appointment } from '@/types'; import { database } from '@/utils/database'; import { api } from '@/utils/api'; import dayjs from 'dayjs'; const { Title, Text, Paragraph } = Typography; const { TextArea } = Input; const { TabPane } = Tabs; const { Option } = Select; interface AppointmentDetailProps {} const AppointmentDetail: React.FC = () => { const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); const [appointment, setAppointment] = useState(null); const [loading, setLoading] = useState(true); const [editModalVisible, setEditModalVisible] = useState(false); const [cancelModalVisible, setCancelModalVisible] = useState(false); const [form] = Form.useForm(); useEffect(() => { if (id) { loadAppointmentDetails(); } }, [id]); const loadAppointmentDetails = async () => { try { setLoading(true); await database.connect(); // 模拟获取预约详情 const mockAppointment: Appointment = { id: id!, userId: 'user_1', translatorId: 'translator_1', title: '商务会议翻译', description: '重要客户会议,需要专业的商务翻译服务,涉及合同条款和技术细节讨论。', type: 'human', sourceLanguage: 'zh-CN', targetLanguage: 'en-US', startTime: '2024-01-20T14:00:00Z', endTime: '2024-01-20T16:00:00Z', status: 'confirmed', cost: 200.00, meetingUrl: 'https://meet.example.com/room/abc123', notes: '客户要求准时开始,请提前5分钟进入会议室', reminderSent: true, createdAt: '2024-01-15T10:00:00Z', updatedAt: '2024-01-15T10:00:00Z', }; setAppointment(mockAppointment); // 填充表单数据 form.setFieldsValue({ title: mockAppointment.title, description: mockAppointment.description, type: mockAppointment.type, sourceLanguage: mockAppointment.sourceLanguage, targetLanguage: mockAppointment.targetLanguage, startTime: dayjs(mockAppointment.startTime), endTime: dayjs(mockAppointment.endTime), notes: mockAppointment.notes, }); } catch (error) { console.error('加载预约详情失败:', error); message.error('加载预约详情失败'); } finally { setLoading(false); } }; const handleEdit = async (values: any) => { if (!appointment) return; try { const updatedAppointment = { ...appointment, ...values, startTime: values.startTime.toISOString(), endTime: values.endTime.toISOString(), updatedAt: new Date().toISOString(), }; setAppointment(updatedAppointment); setEditModalVisible(false); message.success('预约信息更新成功'); } catch (error) { message.error('更新预约信息失败'); } }; const handleCancel = async () => { if (!appointment) return; try { const updatedAppointment = { ...appointment, status: 'cancelled' as const, updatedAt: new Date().toISOString(), }; setAppointment(updatedAppointment); setCancelModalVisible(false); message.success('预约已取消'); } catch (error) { message.error('取消预约失败'); } }; const handleJoinMeeting = () => { if (appointment?.meetingUrl) { window.open(appointment.meetingUrl, '_blank'); } else { message.warning('会议链接不可用'); } }; const getStatusColor = (status: string) => { const colors = { scheduled: 'orange', confirmed: 'blue', cancelled: 'red', completed: 'green', }; return colors[status as keyof typeof colors] || 'default'; }; const getStatusText = (status: string) => { const texts = { scheduled: '已安排', confirmed: '已确认', cancelled: '已取消', completed: '已完成', }; return texts[status as keyof typeof texts] || status; }; const getTypeIcon = (type: string) => { const icons = { ai: '🤖', human: '👤', video: '📹', sign: '🤟', }; return icons[type as keyof typeof icons] || '📞'; }; const getTypeText = (type: string) => { const texts = { ai: 'AI翻译', human: '人工翻译', video: '视频通话', sign: '手语翻译', }; return texts[type as keyof typeof texts] || type; }; const formatDateTime = (dateTime: string) => { return dayjs(dateTime).format('YYYY-MM-DD HH:mm'); }; const getDuration = () => { if (!appointment) return ''; const start = dayjs(appointment.startTime); const end = dayjs(appointment.endTime); const duration = end.diff(start, 'minute'); const hours = Math.floor(duration / 60); const minutes = duration % 60; return hours > 0 ? `${hours}小时${minutes}分钟` : `${minutes}分钟`; }; const getTimelineData = () => { if (!appointment) return []; const timeline = [ { color: 'green', children: (
预约创建
{formatDateTime(appointment.createdAt)}
), }, ]; if (appointment.status === 'confirmed') { timeline.push({ color: 'blue', children: (
预约确认
{formatDateTime(appointment.updatedAt)}
), }); } if (appointment.reminderSent) { timeline.push({ color: 'orange', children: (
提醒已发送
会议前24小时
), }); } if (appointment.status === 'completed') { timeline.push({ color: 'green', children: (
服务完成
{formatDateTime(appointment.endTime)}
), }); } if (appointment.status === 'cancelled') { timeline.push({ color: 'red', children: (
预约取消
{formatDateTime(appointment.updatedAt)}
), }); } return timeline; }; if (loading) { return (
加载预约详情...
); } if (!appointment) { return (
预约记录不存在
); } const isUpcoming = dayjs(appointment.startTime).isAfter(dayjs()); const canEdit = appointment.status !== 'cancelled' && appointment.status !== 'completed'; const canJoin = appointment.status === 'confirmed' && appointment.meetingUrl && dayjs().isAfter(dayjs(appointment.startTime).subtract(5, 'minute')) && dayjs().isBefore(dayjs(appointment.endTime)); return (
{/* 头部导航 */}
预约详情 #{appointment.id}
{/* 快速操作按钮 */} {canJoin && ( )} {canEdit && ( )} {canEdit && ( )} {appointment.meetingUrl && ( )} {/* 基本信息卡片 */} {appointment.title} : appointment.status === 'cancelled' ? : }> {getStatusText(appointment.status)} {getTypeIcon(appointment.type)} {getTypeText(appointment.type)} {appointment.sourceLanguage} {appointment.targetLanguage} ¥{appointment.cost.toFixed(2)} {formatDateTime(appointment.startTime)} {formatDateTime(appointment.endTime)} {getDuration()} } /> {appointment.translatorId || '待分配'} {appointment.meetingUrl && ( {appointment.meetingUrl} )} {appointment.description && (
预约描述: {appointment.description}
)} {appointment.notes && (
备注信息: {appointment.notes}
)}
{/* 详细信息标签页 */} 时间线 } key="timeline" >
沟通记录 } key="communication" >
暂无沟通记录
服务详情 } key="service" >
{getDuration()} ¥{appointment.cost.toFixed(2)} 已支付 {appointment.reminderSent ? ( 已发送提醒 ) : ( 未发送提醒 )}
{/* 编辑预约弹窗 */} setEditModalVisible(false)} footer={null} width={600} >