完善运营端报备流程与页面标题

This commit is contained in:
hectorzhao
2026-06-30 18:32:18 +08:00
parent b2e42ebd82
commit 47e603d7d3
40 changed files with 917 additions and 83 deletions
+136
View File
@@ -0,0 +1,136 @@
import { useMemo, useState } from 'react';
import { Clock3, Eye, Search } from 'lucide-react';
import { Breadcrumb, Button, DateRangeInput, Input, Modal, Select, Table, Tag, type DateRangeValue, type TableColumn } from '@/components/ui';
type RecordStatus = 'unreported' | 'reporting' | 'success' | 'failed' | 'withdrawn' | 'abandoned';
type ReportRecord = {
id: string;
taskId: string;
channel: string;
enterprise: string;
type: '签名' | '引流信息';
content: string;
carrier: '移动' | '联通' | '电信';
status: RecordStatus;
submittedAt: string;
reportedAt?: string;
updatedAt: string;
reason?: string;
};
const statusMeta: Record<RecordStatus, { label: string; tone: 'neutral' | 'info' | 'success' | 'warning' | 'danger' }> = {
unreported: { label: '未报备', tone: 'neutral' },
reporting: { label: '报备中', tone: 'warning' },
success: { label: '报备成功', tone: 'success' },
failed: { label: '报备失败', tone: 'danger' },
withdrawn: { label: '被清退', tone: 'danger' },
abandoned: { label: '放弃报备', tone: 'warning' },
};
const statusOptions = [
{ label: '全部状态', value: 'all' },
{ label: '未报备', value: 'unreported' },
{ label: '报备中', value: 'reporting' },
{ label: '报备成功', value: 'success' },
{ label: '报备失败', value: 'failed' },
{ label: '被清退', value: 'withdrawn' },
{ label: '放弃报备', value: 'abandoned' },
];
const carrierOptions = [
{ label: '全部运营商', value: 'all' },
{ label: '移动', value: '移动' },
{ label: '联通', value: '联通' },
{ label: '电信', value: '电信' },
];
const initialRecords: ReportRecord[] = [
{ id: 'RPT-REC-001', taskId: 'RPT-TASK-20260628-003', channel: '移动-行北-上海甲医院-38', enterprise: '超感世纪互三网', type: '签名', content: '【促销活动】', carrier: '移动', status: 'success', submittedAt: '2026-06-28 12:20:16', reportedAt: '2026-06-29 10:05:44', updatedAt: '2026-06-29 10:05:44' },
{ id: 'RPT-REC-002', taskId: 'RPT-TASK-20260629-006', channel: '联通-行政-杭州甲医院-37', enterprise: '重庆进载数智', type: '引流信息', content: 'https://service.example.com', carrier: '联通', status: 'reporting', submittedAt: '2026-06-29 16:02:11', updatedAt: '2026-06-29 16:02:11' },
{ id: 'RPT-REC-003', taskId: 'RPT-TASK-20260629-006', channel: '联通-行政-杭州甲医院-37', enterprise: '重庆进载数智', type: '签名', content: '【客户服务】', carrier: '联通', status: 'failed', submittedAt: '2026-06-29 16:02:11', reportedAt: '2026-06-30 09:12:35', updatedAt: '2026-06-30 09:12:35', reason: '责任人身份证照片不清晰。' },
{ id: 'RPT-REC-004', taskId: 'RPT-TASK-20260630-001', channel: '行北-集市三甲医院-39', enterprise: '上海XXXXX科技有限公司', type: '签名', content: '【科技公司】', carrier: '移动', status: 'unreported', submittedAt: '2026-06-30 09:12:00', updatedAt: '2026-06-30 09:12:00' },
];
function RecordDetailModal({ record, onClose }: { record: ReportRecord; onClose: () => void }) {
return (
<Modal footer={<Button onClick={onClose}></Button>} onClose={onClose} open size="xl" title={<div className="template-modal-title"><h2></h2><p>{record.id}</p></div>}>
<div className="report-record-detail">
<div className="detail-grid">
<div><span></span><strong>{record.taskId}</strong></div>
<div><span></span><strong>{record.channel}</strong></div>
<div><span></span><strong>{record.enterprise}</strong></div>
<div><span></span><strong>{record.type} {record.content}</strong></div>
<div><span></span><strong>{record.carrier}</strong></div>
<div><span></span><Tag tone={statusMeta[record.status].tone}>{statusMeta[record.status].label}</Tag></div>
<div><span></span><strong>{record.submittedAt}</strong></div>
<div><span></span><strong>{record.reportedAt ?? '-'}</strong></div>
<div className="detail-grid__wide"><span>/</span><strong>{record.reason ?? '-'}</strong></div>
</div>
<section className="report-history">
<h3><Clock3 size={17} /></h3>
<div><span>{record.submittedAt}</span><strong></strong><em></em></div>
<div><span>{record.reportedAt ?? record.updatedAt}</span><strong>{statusMeta[record.status].label}</strong><em>{record.reason ?? '运营商回执同步。'}</em></div>
</section>
</div>
</Modal>
);
}
export function AdminReportRecordsPage() {
const [records] = useState(initialRecords);
const [keyword, setKeyword] = useState('');
const [carrier, setCarrier] = useState('all');
const [status, setStatus] = useState('all');
const [dateRange, setDateRange] = useState<DateRangeValue>({});
const [detail, setDetail] = useState<ReportRecord | null>(null);
const filteredRecords = useMemo(() => records.filter((record) => {
const text = `${record.taskId}${record.channel}${record.enterprise}${record.content}`;
const date = record.submittedAt.slice(0, 10);
return (!keyword || text.includes(keyword))
&& (carrier === 'all' || record.carrier === carrier)
&& (status === 'all' || record.status === status)
&& (!dateRange.start || date >= dateRange.start)
&& (!dateRange.end || date <= dateRange.end);
}), [carrier, dateRange.end, dateRange.start, keyword, records, status]);
const columns: Array<TableColumn<ReportRecord>> = [
{ key: 'object', title: '报备对象', width: '260px', render: (record) => <div className="admin-task-enterprise"><strong>{record.content}</strong><span>{record.type} / {record.enterprise}</span></div> },
{ key: 'task', title: '任务编号', width: '190px', render: (record) => <strong className="admin-task-id">{record.taskId}</strong> },
{ key: 'channel', title: '通道', width: '230px', render: (record) => record.channel },
{ key: 'carrier', title: '运营商', width: '90px', render: (record) => <Tag tone="info">{record.carrier}</Tag> },
{ key: 'status', title: '状态', width: '110px', render: (record) => <Tag tone={statusMeta[record.status].tone}>{statusMeta[record.status].label}</Tag> },
{ key: 'time', title: '时间', width: '190px', render: (record) => <div className="report-task-time"><span> {record.submittedAt}</span><span> {record.reportedAt ?? '-'}</span></div> },
{ key: 'reason', title: '备注', render: (record) => record.reason ?? '-' },
{ key: 'actions', title: '操作', align: 'right', width: '110px', render: (record) => <Button icon={<Eye size={14} />} onClick={() => setDetail(record)} size="sm" variant="ghost"></Button> },
];
return (
<section className="page-stack admin-sms-task-page report-record-page">
<div className="page-heading">
<div>
<Breadcrumb items={['报备任务', '报备记录']} />
<h1></h1>
</div>
</div>
<div className="surface admin-task-filter">
<Input label="任务/通道/企业/签名" onChange={(event) => setKeyword(event.target.value)} placeholder="请输入关键字" value={keyword} />
<Select label="运营商" onChange={(event) => setCarrier(event.target.value)} options={carrierOptions} value={carrier} />
<Select label="报备状态" onChange={(event) => setStatus(event.target.value)} options={statusOptions} value={status} />
<DateRangeInput label="提交时间" onChange={setDateRange} value={dateRange} />
<div className="admin-task-filter__actions">
<Button icon={<Search size={16} />}></Button>
<Button onClick={() => { setKeyword(''); setCarrier('all'); setStatus('all'); setDateRange({}); }} variant="ghost"></Button>
</div>
</div>
<div className="surface admin-task-table-card report-task-table-card">
<Table columns={columns} data={filteredRecords} emptyText="暂无报备记录" rowKey="id" />
</div>
{detail ? <RecordDetailModal onClose={() => setDetail(null)} record={detail} /> : null}
</section>
);
}