import { useMemo, useState } from 'react'; import { BarChart3, CalendarClock, Eye, FileImage, ImageIcon, Search, TrendingUp } from 'lucide-react'; import { Breadcrumb, Button, DateRangeInput, DetailInfoGrid, DetailProgressStats, DetailSection, DetailTitle, getRateTone, Input, Modal, Pagination, ProgressBar, RateCard, RateOverview, Select, Table, Tag, type DateRangeValue, type TableColumn, } from '@/components/ui'; type MmsTaskStatus = 'completed' | 'sending' | 'terminated' | 'failed'; type SendType = 'immediate' | 'scheduled'; type CarrierStat = { name: string; success: number; total: number; rate: number; }; type CityStat = { city: string; total: number; success: number; }; type MmsTask = { id: string; enterprise: string; applicationName: string; submittedAt: string; title: string; content: string; image: string; attachment: string; phoneCount: number; sentCount: number; totalCount: number; sendType: SendType; scheduledAt?: string; status: MmsTaskStatus; carrierStats: CarrierStat[]; cityStats: CityStat[]; }; const statusToneMap: Record = { completed: 'success', sending: 'info', terminated: 'neutral', failed: 'danger', }; const statusLabelMap: Record = { completed: '已完成', sending: '发送中', terminated: '已终止', failed: '失败', }; const sendTypeLabels: Record = { immediate: '立即发送', scheduled: '定时发送', }; const defaultCarrierStats: CarrierStat[] = [ { name: '中国移动', success: 1450, total: 1502, rate: 96.5 }, { name: '中国联通', success: 1138, total: 1200, rate: 94.8 }, { name: '中国电信', success: 762, total: 800, rate: 95.2 }, ]; const defaultCityStats: CityStat[] = [ { city: '成都', total: 1250, success: 1200 }, { city: '重庆', total: 1000, success: 950 }, { city: '绵阳', total: 600, success: 570 }, { city: '泸州', total: 500, success: 475 }, { city: '宜宾', total: 300, success: 285 }, ]; const taskSeed: MmsTask[] = [ { id: 'MMS202603120001', enterprise: '四川骠骑企业管理', applicationName: '营销应用1', submittedAt: '2026-03-12 09:30:15', title: '春季新品发布会邀请函', content: '【骠骑科技】尊敬的客户,我们诚挚邀请您参加春季新品发布会,现场将展示多款创新产品,精彩活动等您参与!活动时间:3月20日下午2点,期待您的光临!', image: 'https://images.unsplash.com/photo-1519671482749-fd09be7ccebf?auto=format&fit=crop&w=500&q=80', attachment: '3张图片', phoneCount: 5000, sentCount: 3500, totalCount: 5000, sendType: 'immediate', status: 'sending', carrierStats: defaultCarrierStats, cityStats: defaultCityStats, }, { id: 'MMS202603120002', enterprise: '重庆进载数智', applicationName: '通知应用', submittedAt: '2026-03-12 10:15:00', title: '会员升级通知', content: '【进载数智】尊敬的VIP会员,恭喜您的会员等级已升级至钻石级别!查看您的专属权益,享受更多优质服务。', image: 'https://images.unsplash.com/photo-1500530855697-b586d89ba3ee?auto=format&fit=crop&w=500&q=80', attachment: '2张图片', phoneCount: 3000, sentCount: 3000, totalCount: 3000, sendType: 'scheduled', scheduledAt: '2026-03-13 08:00:00', status: 'completed', carrierStats: defaultCarrierStats, cityStats: defaultCityStats, }, { id: 'MMS202603120003', enterprise: '超感世纪三三网', applicationName: '推广应用2', submittedAt: '2026-03-12 11:20:00', title: '限时优惠活动', content: '【超感世纪】春季大促来袭!全场商品5折起,精选商品低至3折!更有满减优惠,买一送一活动等您参与。', image: 'https://images.unsplash.com/photo-1607083206968-13611e3d76db?auto=format&fit=crop&w=500&q=80', attachment: '4张图片', phoneCount: 8000, sentCount: 6000, totalCount: 8000, sendType: 'immediate', status: 'sending', carrierStats: defaultCarrierStats, cityStats: defaultCityStats, }, { id: 'MMS202603120004', enterprise: '重庆香惠慧', applicationName: '客服应用', submittedAt: '2026-03-12 14:05:00', title: '产品使用指南', content: '【香惠慧】感谢您选择我们的产品!为了帮助您更好地了解和使用我们的服务,特为您准备了产品使用指南。', image: 'https://images.unsplash.com/photo-1484480974693-6ca0a78fb36b?auto=format&fit=crop&w=500&q=80', attachment: '1张图片', phoneCount: 2000, sentCount: 2000, totalCount: 2000, sendType: 'scheduled', scheduledAt: '2026-03-12 16:00:00', status: 'completed', carrierStats: defaultCarrierStats, cityStats: defaultCityStats, }, { id: 'MMS202603120005', enterprise: '四川骠骑企业管理', applicationName: '活动推广', submittedAt: '2026-03-12 15:30:00', title: '周末特惠活动', content: '【骠骑科技】周末特惠活动开始啦!精美图片抢先看,超值优惠不容错过!点击查看活动详情。', image: 'https://images.unsplash.com/photo-1607082350899-7e105aa886ae?auto=format&fit=crop&w=500&q=80', attachment: '3张图片', phoneCount: 4000, sentCount: 1000, totalCount: 4000, sendType: 'immediate', status: 'terminated', carrierStats: defaultCarrierStats, cityStats: defaultCityStats, }, { id: 'MMS202603110006', enterprise: '重庆进载数智', applicationName: '系统通知', submittedAt: '2026-03-11 17:45:00', title: '系统维护通知', content: '【进载数智】系统维护通知:我们将于今晚进行系统升级,预计耗时2小时。维护期间部分服务可能受影响。', image: 'https://images.unsplash.com/photo-1516321318423-f06f85e504b3?auto=format&fit=crop&w=500&q=80', attachment: '1张图片', phoneCount: 6000, sentCount: 4000, totalCount: 6000, sendType: 'scheduled', scheduledAt: '2026-03-11 20:00:00', status: 'failed', carrierStats: defaultCarrierStats, cityStats: defaultCityStats, }, ]; function formatNumber(value: number) { return value.toLocaleString('zh-CN'); } function getProgress(task: MmsTask) { return Math.round((task.sentCount / task.totalCount) * 100); } function getDeliveredCount(task: MmsTask) { if (task.status === 'completed') { return Math.round(task.totalCount * 0.96); } if (task.status === 'failed') { return Math.round(task.sentCount * 0.82); } return Math.round(task.sentCount * 0.95); } function MmsContent({ task }: { task: MmsTask }) { return (
{task.title}
{task.title}

{task.content}

); } function TaskDetailModal({ task, onClose }: { task: MmsTask; onClose: () => void }) { const progress = getProgress(task); const deliveredCount = getDeliveredCount(task); const overallRate = (deliveredCount / task.totalCount) * 100; return ( 关闭} onClose={onClose} open size="xl" title={} >
{statusLabelMap[task.status]}}> {task.title}
{task.title}

{task.content}

附件:{task.attachment}
), full: true, }, ]} /> 按运营商统计成功率}>
{task.carrierStats.map((item) => ( {formatNumber(item.success)}/ {formatNumber(item.total)}} rate={item.rate} title={item.name} tone={getRateTone(item.rate)} /> ))}

按城市统计成功率

{task.cityStats.map((item) => { const rate = (item.success / item.total) * 100; return (
{item.city} {formatNumber(item.success)} / {formatNumber(item.total)} {rate.toFixed(1)}%
); })}
); } function PreviewModal({ task, onClose }: { task: MmsTask; onClose: () => void }) { return ( 关闭} onClose={onClose} open title={

彩信预览

{task.id}

} >
{task.title}

{task.title}

{task.content}

{task.attachment}图文彩信
); } export function AdminMmsTaskProgressPage() { const [keyword, setKeyword] = useState(''); const [enterprise, setEnterprise] = useState('all'); const [application, setApplication] = useState('all'); const [submittedDateRange, setSubmittedDateRange] = useState({}); const [selectedTask, setSelectedTask] = useState(null); const [previewTask, setPreviewTask] = useState(null); const enterpriseOptions = useMemo(() => { const names = Array.from(new Set(taskSeed.map((item) => item.enterprise))); return [{ label: '全部企业', value: 'all' }, ...names.map((name) => ({ label: name, value: name }))]; }, []); const applicationOptions = useMemo(() => { const names = Array.from(new Set(taskSeed.filter((item) => enterprise === 'all' || item.enterprise === enterprise).map((item) => item.applicationName))); return [{ label: '全部应用', value: 'all' }, ...names.map((name) => ({ label: name, value: name }))]; }, [enterprise]); const filteredTasks = useMemo( () => taskSeed.filter((item) => { const submittedDate = item.submittedAt.slice(0, 10); const matchesKeyword = !keyword || item.id.includes(keyword); const matchesEnterprise = enterprise === 'all' || item.enterprise === enterprise; const matchesApplication = application === 'all' || item.applicationName === application; const matchesStartDate = !submittedDateRange.start || submittedDate >= submittedDateRange.start; const matchesEndDate = !submittedDateRange.end || submittedDate <= submittedDateRange.end; return matchesKeyword && matchesEnterprise && matchesApplication && matchesStartDate && matchesEndDate; }), [application, enterprise, keyword, submittedDateRange.end, submittedDateRange.start], ); function resetFilters() { setKeyword(''); setEnterprise('all'); setApplication('all'); setSubmittedDateRange({}); } const columns: Array> = [ { key: 'id', title: '任务编号', width: '150px', render: (record) => {record.id} }, { key: 'enterprise', title: '企业/应用', width: '180px', render: (record) => (
{record.enterprise} {record.applicationName}
), }, { key: 'submittedAt', title: '提交时间', width: '116px', render: (record) => {record.submittedAt.slice(0, 10)}
{record.submittedAt.slice(11, 16)}
}, { key: 'content', title: '模板内容', width: '420px', render: (record) => }, { key: 'phoneCount', title: '号码数', align: 'right', width: '90px', render: (record) => {formatNumber(record.phoneCount)} }, { key: 'sendType', title: '发送方式', width: '150px', render: (record) => (
{record.sendType === 'scheduled' ? : null} {sendTypeLabels[record.sendType]} {record.scheduledAt ? {record.scheduledAt.slice(0, 10)}
{record.scheduledAt.slice(11, 16)}
: null}
), }, { key: 'progress', title: '进度', width: '180px', render: (record) => { const progress = getProgress(record); return (
{formatNumber(record.sentCount)}/{formatNumber(record.totalCount)} {progress}%
); }, }, { key: 'status', title: '状态', width: '100px', render: (record) => {statusLabelMap[record.status]} }, { key: 'actions', title: '操作', align: 'right', width: '160px', render: (record) => (
), }, ]; return (

彩信任务进度

setKeyword(event.target.value)} placeholder="请输入任务编号" value={keyword} /> setApplication(event.target.value)} options={applicationOptions} value={application} />
{selectedTask ? setSelectedTask(null)} task={selectedTask} /> : null} {previewTask ? setPreviewTask(null)} task={previewTask} /> : null} ); }