'use client'; import React, { useState } from 'react'; import { t } from '@/i18n/locales'; import { useApi } from '@/lib/use-api'; /** * SMS 发送日志查看页面 * * 管理员可按手机号搜索 SMS 发送记录 */ interface SmsLogItem { id: string; phone: string; type: string; status: string; provider: string; createdAt: string; } interface SmsLogsResponse { items: SmsLogItem[]; total: number; } const loadingBox: React.CSSProperties = { display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 40, color: 'var(--color-text-tertiary)', font: 'var(--text-body)', }; export const SmsLogPage: React.FC = () => { const [phone, setPhone] = useState(''); const [searchPhone, setSearchPhone] = useState(''); const [limit] = useState(20); const [offset] = useState(0); const { data, isLoading, error } = useApi( searchPhone ? '/api/v1/admin/sms/logs' : null, { params: { phone: searchPhone, limit, offset } }, ); const logs = data?.items ?? []; const handleSearch = () => { setSearchPhone(phone.trim()); }; const typeBadge = (type: string) => { const map: Record = { REGISTER: { bg: 'var(--color-primary)', color: 'white', label: t('sms_type_register') }, LOGIN: { bg: 'var(--color-info)', color: 'white', label: t('sms_type_login') }, RESET_PASSWORD: { bg: 'var(--color-warning)', color: 'white', label: t('sms_type_reset') }, CHANGE_PHONE: { bg: 'var(--color-success)', color: 'white', label: t('sms_type_change_phone') }, }; const m = map[type] ?? { bg: 'var(--color-gray-400)', color: 'white', label: type }; return ( {m.label} ); }; const statusBadge = (status: string) => { const isSuccess = status === 'SUCCESS' || status === 'SENT'; return ( {isSuccess ? t('sms_status_sent') : t('sms_status_failed')} ); }; return (

{t('sms_log_title')}

{/* Search */}
setPhone(e.target.value)} onKeyDown={e => e.key === 'Enter' && handleSearch()} style={{ flex: 1, maxWidth: 360, height: 40, border: '1px solid var(--color-border)', borderRadius: 'var(--radius-sm)', padding: '0 16px', font: 'var(--text-body)', }} />
{/* Hint when no search */} {!searchPhone && (
{t('sms_search_hint')}
)} {/* Table */} {searchPhone && (error ? (
Error: {error.message}
) : isLoading ? (
Loading...
) : (
{[t('sms_log_phone'), t('sms_log_type'), t('sms_log_status'), t('sms_log_provider'), t('sms_log_time')].map(h => ( ))} {logs.length === 0 ? ( ) : logs.map(log => ( ))}
{h}
{t('sms_no_logs')}
{log.phone} {typeBadge(log.type)} {statusBadge(log.status)} {log.provider} {log.createdAt}
))}
); };