'use client'; import { useEffect, useState } from 'react'; import api from '@/lib/api'; import { Loader2, MessageSquare, AlertCircle, Clock, CheckCircle, XCircle, ArrowRight, Eye, Search, FileText } from 'lucide-react'; import Pagination from '@/components/common/Pagination'; import { UserTicket } from './UserTicketDetailModal'; import { useLanguage } from '@/lib/i18n/LanguageContext'; // 1. 引入 LocalTime 组件 import LocalTime from '@/components/common/LocalTime'; interface TicketListProps { onViewDetail: (ticket: UserTicket) => void; refreshTrigger?: number; } interface TicketData extends UserTicket { id: number; order_id: string; type: 'refund' | 'dispute' | 'change_request'; reason: string; status: 'pending' | 'info_required' | 'resolved' | 'rejected'; admin_comment?: string; created_at: string; } export default function TicketList({ onViewDetail, refreshTrigger }: TicketListProps) { const { t } = useLanguage(); const [loading, setLoading] = useState(true); const [tickets, setTickets] = useState([]); const [page, setPage] = useState(1); const [pageSize] = useState(5); const [total, setTotal] = useState(0); const [keyword, setKeyword] = useState(''); useEffect(() => { fetchTickets(1); }, [refreshTrigger]); const fetchTickets = async (targetPage: number) => { try { setLoading(true); const res = await api.get('/api/vas/ticket/list_by_user', { params: { page: targetPage, size: pageSize, keyword: keyword } }); const data = res.data.data; if (data && Array.isArray(data.items)) { setTickets(data.items); setTotal(data.total || 0); } else { setTickets([]); setTotal(0); } setPage(targetPage); } catch (error) { console.error("Failed to fetch tickets", error); setTickets([]); } finally { setLoading(false); } }; const handleSearch = () => { fetchTickets(1); }; const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter') handleSearch(); }; const getStatusConfig = (status: string) => { const label = t(`ticket.status.${status}`) !== `ticket.status.${status}` ? t(`ticket.status.${status}`) : status; switch (status) { case 'pending': return { text: label, color: 'text-yellow-700 bg-yellow-50 border-yellow-200', icon: Clock }; case 'info_required': return { text: label, color: 'text-blue-700 bg-blue-50 border-blue-200', icon: AlertCircle }; case 'resolved': return { text: label, color: 'text-green-700 bg-green-50 border-green-200', icon: CheckCircle }; case 'rejected': return { text: label, color: 'text-red-700 bg-red-50 border-red-200', icon: XCircle }; default: return { text: label, color: 'text-gray-600 bg-gray-50 border-gray-200', icon: MessageSquare }; } }; const getTypeText = (type: string) => { const key = `ticket.types.${type}`; return t(key) !== key ? t(key) : type; }; return (
{/* Top Toolbar */}
setKeyword(e.target.value)} onKeyDown={handleKeyDown} />
{/* Ticket List */}

{t('ticket.my_tickets')}

{t('common.total')}: {total}
{loading ? (
) : tickets.length === 0 ? (

{t('ticket.empty_title')}

{t('ticket.empty_desc')}

) : (
{tickets.map((ticket) => { const status = getStatusConfig(ticket.status); const StatusIcon = status.icon; const isActionRequired = ticket.status === 'info_required'; return (
{/* Left Info */}
{getTypeText(ticket.type)} {status.text} #{ticket.id}
{ticket.reason}
{t('ticket.order_id')}: {ticket.order_id} {/* 2. 使用 LocalTime 组件 */}
{/* Right Actions */}
{isActionRequired ? ( ) : ( )}
{/* Admin Feedback */} {ticket.admin_comment && (
{t('ticket.latest_feedback')}: {ticket.admin_comment}
)}
); })}
)} fetchTickets(p)} />
); }