fix: connect remaining sms pages to real backend

This commit is contained in:
hectorzhao
2026-07-02 19:30:04 +08:00
parent 06562e42dd
commit 131f344ac4
50 changed files with 2074 additions and 6400 deletions
+52 -59
View File
@@ -1,84 +1,73 @@
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 { Breadcrumb, Button, Input, Modal, Select, Table, Textarea, type TableColumn } from '@/components/ui';
import { adminApi, type DictionaryItem, type TenantOption } from '@/api/adminApi';
type EnterpriseBlacklistItem = {
id: string;
enterprise: string;
application: string;
phone: string;
createdAt: string;
reason: string;
expiredAt: string;
type EnterpriseBlacklistItem = DictionaryItem & {
tenantId?: string;
tenant?: TenantOption;
phoneNumber?: string;
reason?: string | null;
};
const initialItems: EnterpriseBlacklistItem[] = [
{ id: 'EBL20260630001', enterprise: '四川骠骑企业管理', application: '营销应用1', phone: '13675569095', createdAt: '2026-06-28 10:12:05', reason: '用户回复退订', expiredAt: '2026-12-28 23:59:59' },
{ id: 'EBL20260630002', enterprise: '重庆进载数智', application: '通知应用', phone: '18607638087', createdAt: '2026-06-27 15:34:22', reason: '投诉拦截', expiredAt: '2026-09-27 23:59:59' },
{ id: 'EBL20260630003', enterprise: '超感世纪三三网', application: '推广应用2', phone: '15250668026', createdAt: '2026-06-25 09:18:41', reason: '运营手动加入', expiredAt: '2026-08-25 23:59:59' },
{ id: 'EBL20260630004', enterprise: '重庆香惠慧', application: '客服应用', phone: '18800000555', createdAt: '2026-06-24 18:01:10', reason: '敏感投诉号码', expiredAt: '2026-07-24 23:59:59' },
];
function nowText() {
return new Date().toLocaleString('zh-CN', { hour12: false }).replace(/\//g, '-');
}
export function AdminEnterpriseBlacklistPage() {
const [items, setItems] = useState(initialItems);
const [items, setItems] = useState<EnterpriseBlacklistItem[]>([]);
const [tenants, setTenants] = useState<TenantOption[]>([]);
const [keyword, setKeyword] = useState('');
const [enterprise, setEnterprise] = useState('');
const [application, setApplication] = useState('');
const [tenantId, setTenantId] = useState('');
const [phone, setPhone] = useState('');
const [reason, setReason] = useState('');
const [expiredAt, setExpiredAt] = useState('');
const [modalOpen, setModalOpen] = useState(false);
const [error, setError] = useState('');
function loadData() {
Promise.all([adminApi.listEnterpriseBlacklist({ keyword }), adminApi.listTenants()])
.then(([blacklist, tenantItems]) => {
setItems(blacklist as EnterpriseBlacklistItem[]);
setTenants(tenantItems);
setError('');
})
.catch((failure: Error) => setError(failure.message || '企业黑名单加载失败'));
}
useEffect(() => {
loadData();
}, []);
const filteredItems = useMemo(() => items.filter((item) => {
const text = [item.enterprise, item.application, item.phone, item.reason].join(' ');
const text = [item.tenant?.name, item.phoneNumber, item.reason, item.status].join(' ');
return !keyword || text.includes(keyword);
}), [items, keyword]);
const columns = useMemo<Array<TableColumn<EnterpriseBlacklistItem>>>(() => [
{ key: 'enterprise', title: '企业名称', width: '180px', render: (record) => <strong>{record.enterprise}</strong> },
{ key: 'application', title: '应用名称', width: '150px', render: (record) => record.application },
{ key: 'phone', title: '手机号码', width: '150px', render: (record) => <strong>{record.phone}</strong> },
{ key: 'createdAt', title: '入库时间', width: '170px', render: (record) => record.createdAt },
{ key: 'reason', title: '入库原因', render: (record) => record.reason },
{ key: 'expiredAt', title: '过期时间', width: '170px', render: (record) => record.expiredAt },
{ key: 'enterprise', title: '企业名称', width: '180px', render: (record) => <strong>{record.tenant?.name ?? record.tenantId}</strong> },
{ key: 'phone', title: '手机号码', width: '150px', render: (record) => <strong>{record.phoneNumber}</strong> },
{ key: 'createdAt', title: '入库时间', width: '170px', render: (record) => record.createdAt ?? '-' },
{ key: 'reason', title: '入库原因', render: (record) => record.reason ?? '-' },
{ key: 'status', title: '状态', width: '110px', 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.deleteEnterpriseBlacklist(record.id).then(loadData).catch((failure: Error) => setError(failure.message))} size="sm" variant="danger">
</Button>
),
},
], []);
function resetForm() {
setEnterprise('');
setApplication('');
setPhone('');
setReason('');
setExpiredAt('');
}
function addItem() {
const nextItem: EnterpriseBlacklistItem = {
id: `EBL${Date.now()}`,
enterprise: enterprise || '未命名企业',
application: application || '默认应用',
phone: phone || '待补充号码',
createdAt: nowText(),
reason: reason || '运营手动加入',
expiredAt: expiredAt || '永久有效',
};
setItems((current) => [nextItem, ...current]);
resetForm();
setModalOpen(false);
adminApi.createEnterpriseBlacklist({ tenantId, phoneNumber: phone, reason, status: 'active' })
.then(() => {
setTenantId('');
setPhone('');
setReason('');
setModalOpen(false);
loadData();
})
.catch((failure: Error) => setError(failure.message || '添加企业黑名单失败'));
}
return (
@@ -90,17 +79,18 @@ export function AdminEnterpriseBlacklistPage() {
</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>
@@ -113,7 +103,7 @@ export function AdminEnterpriseBlacklistPage() {
footer={(
<>
<Button onClick={() => setModalOpen(false)} variant="ghost"></Button>
<Button onClick={addItem}></Button>
<Button disabled={!tenantId || !phone} onClick={addItem}></Button>
</>
)}
onClose={() => setModalOpen(false)}
@@ -121,10 +111,13 @@ export function AdminEnterpriseBlacklistPage() {
title="添加企业黑名单"
>
<div className="admin-security-form">
<Input label="企业名称" onChange={(event) => setEnterprise(event.target.value)} placeholder="请输入企业名称" value={enterprise} />
<Input label="应用名称" onChange={(event) => setApplication(event.target.value)} placeholder="请输入应用名称" value={application} />
<Select
label="企业"
onChange={(event) => setTenantId(event.target.value)}
options={[{ label: '请选择企业', value: '' }, ...tenants.map((item) => ({ label: item.name, value: item.id }))]}
value={tenantId}
/>
<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>