Split customer management modules
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
import { useMemo, useState } from 'react';
|
||||
import { Edit3, Plus, Trash2 } from 'lucide-react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Button, Modal, Table, Tabs, Tag, type TableColumn } from '@/components/ui';
|
||||
|
||||
type SmsApp = {
|
||||
id: string;
|
||||
name: string;
|
||||
enterprise: string;
|
||||
appId: string;
|
||||
enabled: boolean;
|
||||
sentToday: number;
|
||||
deliveryRate: number;
|
||||
unitPrice: number;
|
||||
cmppStatus: 'connected' | 'disconnected' | 'inactive';
|
||||
};
|
||||
|
||||
type MmsApp = Omit<SmsApp, 'cmppStatus'> & {
|
||||
pointPrice: number;
|
||||
};
|
||||
|
||||
type AppKind = 'sms' | 'mms';
|
||||
|
||||
const initialSmsApps: SmsApp[] = [
|
||||
{ id: 'app-1', name: '营销推广平台', enterprise: '上海XXXXX科技有限公司', appId: 'AK_2024010912345678', enabled: true, sentToday: 1500, deliveryRate: 95, unitPrice: 0.05, cmppStatus: 'connected' },
|
||||
{ id: 'app-2', name: '客户服务系统', enterprise: '重庆进载数智', appId: 'AK_2024010987654321', enabled: true, sentToday: 800, deliveryRate: 90, unitPrice: 0.06, cmppStatus: 'disconnected' },
|
||||
{ id: 'app-3', name: '验证码服务', enterprise: '超感世纪互三网', appId: 'AK_2024010811223344', enabled: false, sentToday: 0, deliveryRate: 0, unitPrice: 0.04, cmppStatus: 'inactive' },
|
||||
];
|
||||
|
||||
const initialMmsApps: MmsApp[] = [
|
||||
{ id: 'mms-app-1', name: '营销活动彩信', enterprise: '上海XXXXX科技有限公司', appId: 'MMS_2024020112345678', enabled: true, sentToday: 320, deliveryRate: 92, unitPrice: 0.15, pointPrice: 50 },
|
||||
{ id: 'mms-app-2', name: '节日祝福彩信', enterprise: '重庆进载数智', appId: 'MMS_2024020187654321', enabled: true, sentToday: 180, deliveryRate: 88, unitPrice: 0.12, pointPrice: 30 },
|
||||
{ id: 'mms-app-3', name: '会员权益彩信', enterprise: '四川骠骑企业管理', appId: 'MMS_2024020199001122', enabled: false, sentToday: 0, deliveryRate: 0, unitPrice: 0.18, pointPrice: 60 },
|
||||
];
|
||||
|
||||
function enabledTag(enabled: boolean) {
|
||||
return <Tag tone={enabled ? 'success' : 'neutral'}>{enabled ? '启用' : '停用'}</Tag>;
|
||||
}
|
||||
|
||||
function ConfirmModal({ message, danger, onCancel, onConfirm }: { message: string; danger?: boolean; onCancel: () => void; onConfirm: () => void }) {
|
||||
return (
|
||||
<Modal
|
||||
footer={(
|
||||
<>
|
||||
<Button onClick={onCancel} variant="ghost">取消</Button>
|
||||
<Button onClick={onConfirm} variant={danger ? 'danger' : 'primary'}>确认</Button>
|
||||
</>
|
||||
)}
|
||||
onClose={onCancel}
|
||||
open
|
||||
title="操作确认"
|
||||
>
|
||||
<p className="admin-confirm-text">{message}</p>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export function AdminEnterpriseApplicationsPage() {
|
||||
const navigate = useNavigate();
|
||||
const [smsApps, setSmsApps] = useState(initialSmsApps);
|
||||
const [mmsApps, setMmsApps] = useState(initialMmsApps);
|
||||
const [confirmAction, setConfirmAction] = useState<
|
||||
| { action: 'toggle'; kind: AppKind; id: string; name: string; enabled: boolean }
|
||||
| { action: 'delete'; kind: AppKind; id: string; name: string }
|
||||
| null
|
||||
>(null);
|
||||
|
||||
function confirmToggle(kind: AppKind, id: string) {
|
||||
if (kind === 'sms') {
|
||||
setSmsApps((current) => current.map((item) => item.id === id ? { ...item, enabled: !item.enabled } : item));
|
||||
return;
|
||||
}
|
||||
|
||||
setMmsApps((current) => current.map((item) => item.id === id ? { ...item, enabled: !item.enabled } : item));
|
||||
}
|
||||
|
||||
function confirmDelete(kind: AppKind, id: string) {
|
||||
if (kind === 'sms') {
|
||||
setSmsApps((current) => current.filter((item) => item.id !== id));
|
||||
} else {
|
||||
setMmsApps((current) => current.filter((item) => item.id !== id));
|
||||
}
|
||||
}
|
||||
|
||||
function runConfirmedAction() {
|
||||
if (!confirmAction) {
|
||||
return;
|
||||
}
|
||||
if (confirmAction.action === 'toggle') {
|
||||
confirmToggle(confirmAction.kind, confirmAction.id);
|
||||
} else {
|
||||
confirmDelete(confirmAction.kind, confirmAction.id);
|
||||
}
|
||||
setConfirmAction(null);
|
||||
}
|
||||
|
||||
const smsColumns = useMemo<Array<TableColumn<SmsApp>>>(() => [
|
||||
{ key: 'name', title: '应用名称', width: '180px', render: (record) => <strong>{record.name}</strong> },
|
||||
{ key: 'enterprise', title: '企业名称', width: '220px', render: (record) => record.enterprise },
|
||||
{ key: 'appId', title: 'AppID', width: '220px', render: (record) => record.appId },
|
||||
{ key: 'sentToday', title: '今日发送', width: '120px', render: (record) => `${record.sentToday.toLocaleString('zh-CN')} 条` },
|
||||
{ key: 'deliveryRate', title: '到达率', width: '110px', render: (record) => `${record.deliveryRate}%` },
|
||||
{ key: 'unitPrice', title: '单价', width: '100px', render: (record) => `${record.unitPrice.toFixed(3)} 元` },
|
||||
{
|
||||
key: 'cmppStatus',
|
||||
title: 'CMPP状态',
|
||||
width: '130px',
|
||||
render: (record) => (
|
||||
<Tag tone={record.cmppStatus === 'connected' ? 'success' : record.cmppStatus === 'disconnected' ? 'danger' : 'neutral'}>
|
||||
{record.cmppStatus === 'connected' ? '已连接' : record.cmppStatus === 'disconnected' ? '已断开' : '未开通'}
|
||||
</Tag>
|
||||
),
|
||||
},
|
||||
{ key: 'enabled', title: '状态', width: '100px', render: (record) => enabledTag(record.enabled) },
|
||||
{
|
||||
key: 'actions',
|
||||
title: '操作',
|
||||
align: 'right',
|
||||
width: '190px',
|
||||
render: (record) => (
|
||||
<div className="table-actions">
|
||||
<Button icon={<Edit3 size={15} />} onClick={() => navigate(`/admin/customers/2763/sms-apps/${record.id}/edit`)} size="sm" variant="ghost">编辑</Button>
|
||||
<Button onClick={() => setConfirmAction({ action: 'toggle', kind: 'sms', id: record.id, name: record.name, enabled: record.enabled })} size="sm" variant="secondary">
|
||||
{record.enabled ? '停用' : '启用'}
|
||||
</Button>
|
||||
<Button icon={<Trash2 size={15} />} onClick={() => setConfirmAction({ action: 'delete', kind: 'sms', id: record.id, name: record.name })} size="sm" variant="danger">删除</Button>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
], [navigate]);
|
||||
|
||||
const mmsColumns = useMemo<Array<TableColumn<MmsApp>>>(() => [
|
||||
{ key: 'name', title: '应用名称', width: '180px', render: (record) => <strong>{record.name}</strong> },
|
||||
{ key: 'enterprise', title: '企业名称', width: '220px', render: (record) => record.enterprise },
|
||||
{ key: 'appId', title: 'AppID', width: '220px', render: (record) => record.appId },
|
||||
{ key: 'sentToday', title: '今日发送', width: '120px', render: (record) => `${record.sentToday.toLocaleString('zh-CN')} 条` },
|
||||
{ key: 'deliveryRate', title: '到达率', width: '110px', render: (record) => `${record.deliveryRate}%` },
|
||||
{ key: 'unitPrice', title: '单价', width: '100px', render: (record) => `${record.unitPrice.toFixed(3)} 元` },
|
||||
{ key: 'pointPrice', title: '点数', width: '100px', render: (record) => `${record.pointPrice} 分` },
|
||||
{ key: 'enabled', title: '状态', width: '100px', render: (record) => enabledTag(record.enabled) },
|
||||
{
|
||||
key: 'actions',
|
||||
title: '操作',
|
||||
align: 'right',
|
||||
width: '190px',
|
||||
render: (record) => (
|
||||
<div className="table-actions">
|
||||
<Button icon={<Edit3 size={15} />} onClick={() => navigate(`/admin/customers/2763/mms-apps/${record.id}/edit`)} size="sm" variant="ghost">编辑</Button>
|
||||
<Button onClick={() => setConfirmAction({ action: 'toggle', kind: 'mms', id: record.id, name: record.name, enabled: record.enabled })} size="sm" variant="secondary">
|
||||
{record.enabled ? '停用' : '启用'}
|
||||
</Button>
|
||||
<Button icon={<Trash2 size={15} />} onClick={() => setConfirmAction({ action: 'delete', kind: 'mms', id: record.id, name: record.name })} size="sm" variant="danger">删除</Button>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
], [navigate]);
|
||||
|
||||
return (
|
||||
<section className="page-stack admin-customer-split-page">
|
||||
<div className="page-heading">
|
||||
<div>
|
||||
<div className="breadcrumb-line">客户管理 / <strong>企业应用管理</strong></div>
|
||||
<h1>企业应用管理</h1>
|
||||
</div>
|
||||
<Button icon={<Plus size={16} />} onClick={() => navigate('/admin/customers/2763/sms-apps/new')}>添加应用</Button>
|
||||
</div>
|
||||
|
||||
<div className="surface section-stack">
|
||||
<Tabs
|
||||
items={[
|
||||
{ label: '短信应用', value: 'sms', content: <Table columns={smsColumns} data={smsApps} rowKey="id" /> },
|
||||
{ label: '彩信应用', value: 'mms', content: <Table columns={mmsColumns} data={mmsApps} rowKey="id" /> },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{confirmAction ? (
|
||||
<ConfirmModal
|
||||
danger={confirmAction.action === 'delete'}
|
||||
message={confirmAction.action === 'delete'
|
||||
? `确认删除应用“${confirmAction.name}”吗?`
|
||||
: `确认${confirmAction.enabled ? '停用' : '启用'}应用“${confirmAction.name}”吗?`}
|
||||
onCancel={() => setConfirmAction(null)}
|
||||
onConfirm={runConfirmedAction}
|
||||
/>
|
||||
) : null}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user