fix: connect remaining sms pages to real backend
This commit is contained in:
@@ -1,74 +1,66 @@
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { Plus, Search, Trash2 } from 'lucide-react';
|
||||
import { Breadcrumb, Button, Input, Modal, Table, Textarea, type TableColumn } from '@/components/ui';
|
||||
import { adminApi, type DictionaryItem } from '@/api/adminApi';
|
||||
|
||||
type GlobalBlacklistItem = {
|
||||
id: string;
|
||||
phone: string;
|
||||
createdAt: string;
|
||||
reason: string;
|
||||
expiredAt: string;
|
||||
type GlobalBlacklistItem = DictionaryItem & {
|
||||
phoneNumber?: string;
|
||||
reason?: string | null;
|
||||
};
|
||||
|
||||
const initialItems: GlobalBlacklistItem[] = [
|
||||
{ id: 'GBL20260630001', phone: '13500000888', createdAt: '2026-06-28 11:20:05', reason: '多企业投诉号码', expiredAt: '2026-12-28 23:59:59' },
|
||||
{ id: 'GBL20260630002', phone: '13755558888', createdAt: '2026-06-27 16:05:12', reason: '黑名单同步导入', expiredAt: '2026-09-27 23:59:59' },
|
||||
{ id: 'GBL20260630003', phone: '18800000555', createdAt: '2026-06-26 09:44:30', reason: '监管要求拦截', expiredAt: '2027-06-26 23:59:59' },
|
||||
{ id: 'GBL20260630004', phone: '15250668026', createdAt: '2026-06-25 14:12:18', reason: '高频退订', expiredAt: '2026-08-25 23:59:59' },
|
||||
];
|
||||
|
||||
function nowText() {
|
||||
return new Date().toLocaleString('zh-CN', { hour12: false }).replace(/\//g, '-');
|
||||
}
|
||||
|
||||
export function AdminGlobalBlacklistPage() {
|
||||
const [items, setItems] = useState(initialItems);
|
||||
const [items, setItems] = useState<GlobalBlacklistItem[]>([]);
|
||||
const [keyword, setKeyword] = useState('');
|
||||
const [phone, setPhone] = useState('');
|
||||
const [reason, setReason] = useState('');
|
||||
const [expiredAt, setExpiredAt] = useState('');
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
|
||||
function loadData() {
|
||||
adminApi.listGlobalBlacklist({ keyword })
|
||||
.then((data) => {
|
||||
setItems(data as GlobalBlacklistItem[]);
|
||||
setError('');
|
||||
})
|
||||
.catch((failure: Error) => setError(failure.message || '全局黑名单加载失败'));
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
loadData();
|
||||
}, []);
|
||||
|
||||
const filteredItems = useMemo(() => items.filter((item) => {
|
||||
const text = [item.phone, item.reason, item.expiredAt].join(' ');
|
||||
const text = [item.phoneNumber, item.reason, item.status].join(' ');
|
||||
return !keyword || text.includes(keyword);
|
||||
}), [items, keyword]);
|
||||
|
||||
const columns = useMemo<Array<TableColumn<GlobalBlacklistItem>>>(() => [
|
||||
{ key: 'phone', title: '手机号码', width: '180px', render: (record) => <strong>{record.phone}</strong> },
|
||||
{ key: 'createdAt', title: '入库时间', width: '190px', render: (record) => record.createdAt },
|
||||
{ key: 'reason', title: '入库原因', render: (record) => record.reason },
|
||||
{ key: 'expiredAt', title: '过期时间', width: '190px', render: (record) => record.expiredAt },
|
||||
{ key: 'phone', title: '手机号码', width: '180px', render: (record) => <strong>{record.phoneNumber}</strong> },
|
||||
{ key: 'createdAt', title: '入库时间', width: '190px', render: (record) => record.createdAt ?? '-' },
|
||||
{ key: 'reason', title: '入库原因', render: (record) => record.reason ?? '-' },
|
||||
{ key: 'status', title: '状态', width: '120px', render: (record) => record.status ?? '-' },
|
||||
{
|
||||
key: 'actions',
|
||||
title: '操作',
|
||||
width: '110px',
|
||||
align: 'right',
|
||||
render: (record) => (
|
||||
<Button icon={<Trash2 size={15} />} onClick={() => setItems((current) => current.filter((item) => item.id !== record.id))} size="sm" variant="danger">
|
||||
<Button icon={<Trash2 size={15} />} onClick={() => adminApi.deleteGlobalBlacklist(record.id).then(loadData).catch((failure: Error) => setError(failure.message))} size="sm" variant="danger">
|
||||
删除
|
||||
</Button>
|
||||
),
|
||||
},
|
||||
], []);
|
||||
|
||||
function resetForm() {
|
||||
setPhone('');
|
||||
setReason('');
|
||||
setExpiredAt('');
|
||||
}
|
||||
|
||||
function addItem() {
|
||||
const nextItem: GlobalBlacklistItem = {
|
||||
id: `GBL${Date.now()}`,
|
||||
phone: phone || '待补充号码',
|
||||
createdAt: nowText(),
|
||||
reason: reason || '运营手动加入',
|
||||
expiredAt: expiredAt || '永久有效',
|
||||
};
|
||||
setItems((current) => [nextItem, ...current]);
|
||||
resetForm();
|
||||
setModalOpen(false);
|
||||
adminApi.createGlobalBlacklist({ phoneNumber: phone, reason, status: 'active' })
|
||||
.then(() => {
|
||||
setPhone('');
|
||||
setReason('');
|
||||
setModalOpen(false);
|
||||
loadData();
|
||||
})
|
||||
.catch((failure: Error) => setError(failure.message || '添加全局黑名单失败'));
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -80,17 +72,18 @@ export function AdminGlobalBlacklistPage() {
|
||||
</div>
|
||||
<Button icon={<Plus size={16} />} onClick={() => setModalOpen(true)}>添加黑名单</Button>
|
||||
</div>
|
||||
{error ? <p className="form-error">{error}</p> : null}
|
||||
|
||||
<div className="surface admin-security-filter">
|
||||
<Input
|
||||
label="搜索"
|
||||
onChange={(event) => setKeyword(event.target.value)}
|
||||
placeholder="搜索手机号、原因或过期时间"
|
||||
placeholder="搜索手机号、原因或状态"
|
||||
prefix={<Search size={16} />}
|
||||
value={keyword}
|
||||
/>
|
||||
<div className="admin-security-filter__actions">
|
||||
<Button icon={<Search size={16} />}>查询</Button>
|
||||
<Button icon={<Search size={16} />} onClick={loadData}>查询</Button>
|
||||
<Button onClick={() => setKeyword('')} variant="ghost">重置</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -103,7 +96,7 @@ export function AdminGlobalBlacklistPage() {
|
||||
footer={(
|
||||
<>
|
||||
<Button onClick={() => setModalOpen(false)} variant="ghost">取消</Button>
|
||||
<Button onClick={addItem}>确认添加</Button>
|
||||
<Button disabled={!phone} onClick={addItem}>确认添加</Button>
|
||||
</>
|
||||
)}
|
||||
onClose={() => setModalOpen(false)}
|
||||
@@ -112,7 +105,6 @@ export function AdminGlobalBlacklistPage() {
|
||||
>
|
||||
<div className="admin-security-form">
|
||||
<Input label="手机号码" onChange={(event) => setPhone(event.target.value)} placeholder="请输入手机号码" value={phone} />
|
||||
<Input label="过期时间" onChange={(event) => setExpiredAt(event.target.value)} placeholder="例如 2026-12-31 23:59:59" value={expiredAt} />
|
||||
<Textarea label="入库原因" onChange={(event) => setReason(event.target.value)} placeholder="请输入入库原因" rows={3} value={reason} />
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
Reference in New Issue
Block a user