Initial CMPP frontend prototype
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
import { useMemo, useState } from 'react';
|
||||
import { Plus, Search, Trash2 } from 'lucide-react';
|
||||
import { Button, Input, Modal, Select, Table, type TableColumn } from '@/components/ui';
|
||||
|
||||
type PhoneSegment = {
|
||||
id: string;
|
||||
segment: string;
|
||||
carrier: string;
|
||||
province: string;
|
||||
city: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
const initialSegments: PhoneSegment[] = [
|
||||
{ id: 'SEG20260630001', segment: '1367556', carrier: '中国移动', province: '四川省', city: '成都市', createdAt: '2026-06-11 09:30:12', updatedAt: '2026-06-28 15:40:00' },
|
||||
{ id: 'SEG20260630002', segment: '1860763', carrier: '中国联通', province: '重庆市', city: '重庆市', createdAt: '2026-06-12 10:18:44', updatedAt: '2026-06-27 11:22:13' },
|
||||
{ id: 'SEG20260630003', segment: '1525066', carrier: '中国电信', province: '江苏省', city: '南京市', createdAt: '2026-06-15 14:22:31', updatedAt: '2026-06-26 17:05:39' },
|
||||
{ id: 'SEG20260630004', segment: '1501234', carrier: '中国移动', province: '广东省', city: '深圳市', createdAt: '2026-06-18 16:10:25', updatedAt: '2026-06-24 09:15:26' },
|
||||
];
|
||||
|
||||
function createSegmentId() {
|
||||
return `SEG${Date.now()}`;
|
||||
}
|
||||
|
||||
type SegmentFormModalProps = {
|
||||
item?: PhoneSegment;
|
||||
onClose: () => void;
|
||||
onSubmit: (item: PhoneSegment) => void;
|
||||
};
|
||||
|
||||
function SegmentFormModal({ item, onClose, onSubmit }: SegmentFormModalProps) {
|
||||
const [form, setForm] = useState<PhoneSegment>(() => item ?? {
|
||||
id: createSegmentId(),
|
||||
segment: '',
|
||||
carrier: '中国移动',
|
||||
province: '',
|
||||
city: '',
|
||||
createdAt: '2026-06-30 10:00:00',
|
||||
updatedAt: '2026-06-30 10:00:00',
|
||||
});
|
||||
|
||||
function updateField<Key extends keyof PhoneSegment>(key: Key, value: PhoneSegment[Key]) {
|
||||
setForm((current) => ({ ...current, [key]: value }));
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
footer={(
|
||||
<>
|
||||
<Button onClick={onClose} variant="ghost">取消</Button>
|
||||
<Button onClick={() => onSubmit({ ...form, updatedAt: '2026-06-30 10:00:00' })}>保存</Button>
|
||||
</>
|
||||
)}
|
||||
onClose={onClose}
|
||||
open
|
||||
title={item ? '编辑手机号段' : '新增手机号段'}
|
||||
>
|
||||
<div className="admin-system-modal-form">
|
||||
<Input label="手机号段" maxLength={7} onChange={(event) => updateField('segment', event.target.value)} placeholder="手机号码前7位" value={form.segment} />
|
||||
<Select
|
||||
label="运营商"
|
||||
onChange={(event) => updateField('carrier', event.target.value)}
|
||||
options={[
|
||||
{ label: '中国移动', value: '中国移动' },
|
||||
{ label: '中国联通', value: '中国联通' },
|
||||
{ label: '中国电信', value: '中国电信' },
|
||||
]}
|
||||
value={form.carrier}
|
||||
/>
|
||||
<Input label="省份" onChange={(event) => updateField('province', event.target.value)} value={form.province} />
|
||||
<Input label="城市" onChange={(event) => updateField('city', event.target.value)} value={form.city} />
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export function AdminPhoneSegmentsPage() {
|
||||
const [segments, setSegments] = useState(initialSegments);
|
||||
const [keyword, setKeyword] = useState('');
|
||||
const [editingSegment, setEditingSegment] = useState<PhoneSegment | null>(null);
|
||||
const [creating, setCreating] = useState(false);
|
||||
|
||||
const filteredSegments = useMemo(
|
||||
() => segments.filter((segment) => [segment.segment, segment.carrier, segment.province, segment.city].some((value) => value.includes(keyword))),
|
||||
[keyword, segments],
|
||||
);
|
||||
|
||||
function upsertSegment(nextSegment: PhoneSegment) {
|
||||
setSegments((current) => {
|
||||
const exists = current.some((item) => item.id === nextSegment.id);
|
||||
if (exists) {
|
||||
return current.map((item) => (item.id === nextSegment.id ? nextSegment : item));
|
||||
}
|
||||
|
||||
return [nextSegment, ...current];
|
||||
});
|
||||
setEditingSegment(null);
|
||||
setCreating(false);
|
||||
}
|
||||
|
||||
const columns = useMemo<Array<TableColumn<PhoneSegment>>>(() => [
|
||||
{ key: 'segment', title: '手机号段(手机号码前7位)', width: '230px', render: (record) => <strong>{record.segment}</strong> },
|
||||
{ key: 'carrier', title: '运营商', width: '150px', render: (record) => record.carrier },
|
||||
{ key: 'province', title: '省份', width: '140px', render: (record) => record.province },
|
||||
{ key: 'city', title: '城市', width: '140px', render: (record) => record.city },
|
||||
{ key: 'createdAt', title: '创建时间', width: '190px', render: (record) => record.createdAt },
|
||||
{ key: 'updatedAt', title: '更新时间', width: '190px', render: (record) => record.updatedAt },
|
||||
{
|
||||
key: 'actions',
|
||||
title: '操作',
|
||||
width: '150px',
|
||||
align: 'right',
|
||||
render: (record) => (
|
||||
<div className="admin-system-actions">
|
||||
<Button onClick={() => setEditingSegment(record)} size="sm" variant="ghost">编辑</Button>
|
||||
<Button
|
||||
icon={<Trash2 size={15} />}
|
||||
onClick={() => setSegments((current) => current.filter((item) => item.id !== record.id))}
|
||||
size="sm"
|
||||
variant="danger"
|
||||
>
|
||||
删除
|
||||
</Button>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
], []);
|
||||
|
||||
return (
|
||||
<section className="page-stack admin-system-page">
|
||||
<div className="page-heading">
|
||||
<div>
|
||||
<div className="breadcrumb-line">系统管理 / <strong>手机号段库</strong></div>
|
||||
<h1>手机号段库</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="surface admin-system-toolbar">
|
||||
<Input onChange={(event) => setKeyword(event.target.value)} placeholder="搜索手机号段、运营商、省份或城市" prefix={<Search size={16} />} value={keyword} />
|
||||
<Button icon={<Plus size={16} />} onClick={() => setCreating(true)}>新增号段</Button>
|
||||
</div>
|
||||
|
||||
<div className="surface admin-system-table-card">
|
||||
<Table columns={columns} data={filteredSegments} emptyText="暂无手机号段" rowKey="id" />
|
||||
</div>
|
||||
|
||||
{creating ? <SegmentFormModal onClose={() => setCreating(false)} onSubmit={upsertSegment} /> : null}
|
||||
{editingSegment ? <SegmentFormModal item={editingSegment} onClose={() => setEditingSegment(null)} onSubmit={upsertSegment} /> : null}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user