'use client'; import { useState, useEffect, useRef } from 'react'; import api from '@/lib/api'; import { X, Send, User, Headset, Paperclip, Loader2, Clock, CheckCircle, AlertCircle, XCircle } from 'lucide-react'; // 定义工单类型(需导出给列表页使用) export interface UserTicket { id: number; order_id: string; type: string; status: string; reason: string; admin_comment?: string; created_at: string; } interface Message { id: number; ticket_id: number; sender_type: 'user' | 'admin' | 'system'; content: string; created_at: string; } interface UserTicketDetailModalProps { isOpen: boolean; onClose: () => void; ticket: UserTicket | null; } export default function UserTicketDetailModal({ isOpen, onClose, ticket }: UserTicketDetailModalProps) { const [messages, setMessages] = useState([]); const [loadingMsg, setLoadingMsg] = useState(false); const [replyContent, setReplyContent] = useState(''); const [sending, setSending] = useState(false); // 滚动到底部的引用 const messagesEndRef = useRef(null); // 1. 初始化加载消息 useEffect(() => { if (isOpen && ticket) { fetchMessages(); // 可选:设置轮询,每10秒获取新消息 // const interval = setInterval(fetchMessages, 10000); // return () => clearInterval(interval); } }, [isOpen, ticket]); // 2. 滚动到底部 useEffect(() => { scrollToBottom(); }, [messages]); const fetchMessages = async () => { if (!ticket) return; try { setLoadingMsg(true); // API: GET /api/vas/tickets/fetch_message?ticket_id=123&page=1&size=50 const res = await api.get('/api/vas/tickets/fetch_message', { params: { ticket_id: ticket.id, page: 1, size: 100 // 获取最近的100条 } }); const items = res.data.data?.items || []; // 确保按时间正序排列 (旧 -> 新) const sorted = items.sort((a: Message, b: Message) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime() ); setMessages(sorted); } catch (error) { console.error("Fetch messages failed", error); } finally { setLoadingMsg(false); } }; const handleSend = async (e: React.FormEvent) => { e.preventDefault(); if (!replyContent.trim() || !ticket) return; setSending(true); try { // API: POST /api/vas/tickets/send_message?ticket_id=123 await api.post(`/api/vas/tickets/send_message`, { content: replyContent, attachments: null // 暂不支持附件,留空 }, { params: { ticket_id: ticket.id } }); setReplyContent(''); fetchMessages(); // 发送成功后刷新列表 } catch (error) { console.error("Send message failed", error); alert("发送失败,请稍后重试"); } finally { setSending(false); } }; const scrollToBottom = () => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }; // 辅助函数:渲染状态 const renderStatus = (status: string) => { const map: any = { pending: { color: 'text-yellow-600 bg-yellow-50', icon: Clock, text: '待处理' }, info_required: { color: 'text-orange-600 bg-orange-50', icon: AlertCircle, text: '需补充资料' }, resolved: { color: 'text-green-600 bg-green-50', icon: CheckCircle, text: '已解决' }, rejected: { color: 'text-red-600 bg-red-50', icon: XCircle, text: '已拒绝' }, }; const conf = map[status] || { color: 'text-gray-600 bg-gray-50', icon: Clock, text: status }; const Icon = conf.icon; return ( {conf.text} ); }; if (!isOpen || !ticket) return null; return (
{/* 遮罩层 */}
{/* 弹窗主体 */}
{/* 1. 顶部 Header */}

工单 #{ticket.id}

{renderStatus(ticket.status)}

关联订单: {ticket.order_id}

{/* 2. 中间:消息列表 (Scrollable) */}
{/* 原始工单描述 (作为第一条展示) */}
工单创建于 {new Date(ticket.created_at).toLocaleString()}

工单描述

{ticket.reason}
{/* 会话记录 */} {loadingMsg ? (
) : ( messages.map((msg) => { const isMe = msg.sender_type === 'user'; const isSystem = msg.sender_type === 'system'; if (isSystem) { return (
系统消息: {msg.content} - {new Date(msg.created_at).toLocaleTimeString()}
); } return (
{/* 头像 */}
{isMe ? : }
{/* 气泡 */}
{msg.content}
{isMe ? '我' : '客服'} • {new Date(msg.created_at).toLocaleString([], {month:'numeric', day:'numeric', hour:'2-digit', minute:'2-digit'})}
); }) )}
{/* 3. 底部:输入框 */}