Files
lislgosms/src/apps/admin/enterprise-applications/EnterpriseApplicationTable.tsx
T

165 lines
6.2 KiB
TypeScript

import { useMemo } from 'react';
import { Edit3, Settings2, Trash2 } from 'lucide-react';
import { Button, Pagination, Table, Tabs, Tag, type TableColumn } from '@/components/ui';
import { formatAmount } from '@/utils/currency';
import { formatDateTime } from '@/utils/dateTime';
import type { ConfirmAction, SmsApp } from './applicationTypes';
function applicationStatusTag(app: SmsApp) {
if (app.status === 'disabling') {
const detail = app.deactivation;
const title = [
detail?.reason || '等待未完成回执清算',
`等待供应商回执:${detail?.awaitingSupplierReceipt ?? 0}条`,
`等待推送:${detail?.waitingToSend ?? 0}条`,
`等待客户端确认:${detail?.awaitingClientAck ?? 0}条`,
`可重试失败:${detail?.retryableFailures ?? 0}条`,
`待推送上行:${detail?.pendingUplinks ?? 0}条`,
`进入停用中:${formatDateTime(detail?.disablingAt)}`,
`自动停用时间:${formatDateTime(detail?.autoDisableAt)}`,
].join('\n');
return <span aria-label={title} className="application-status-detail" tabIndex={0} title={title}><Tag tone="warning">停用中</Tag></span>;
}
return <Tag tone={app.status === 'active' ? 'success' : 'neutral'}>{app.status === 'active' ? '启用' : '停用'}</Tag>;
}
type EnterpriseApplicationTableProps = {
apps: SmsApp[];
page: number;
pageSize: number;
total: number;
onConfirmAction: (action: ConfirmAction) => void;
onEdit: (app: SmsApp) => void;
onOpenCmppParams: (app: SmsApp) => void;
onOpenConnection: (app: SmsApp) => void;
onOpenDeactivate: (app: SmsApp) => void;
onOpenHttpParams: (app: SmsApp) => void;
onPageChange: (page: number) => void;
};
export function EnterpriseApplicationTable({
apps,
page,
pageSize,
total,
onConfirmAction,
onEdit,
onOpenCmppParams,
onOpenConnection,
onOpenDeactivate,
onOpenHttpParams,
onPageChange,
}: EnterpriseApplicationTableProps) {
const totalPages = Math.max(1, Math.ceil(total / pageSize));
const columns = 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: 'sentToday', title: '今日发送', width: '120px', render: (record) => `${record.sentToday.toLocaleString('zh-CN')} 条` },
{ key: 'deliveryRate', title: '到达率', width: '130px', render: (record) => `${record.deliveryRate}%` },
{ key: 'unitPrice', title: '单价', width: '130px', render: (record) => `${formatAmount(record.unitPrice)} 元` },
{
key: 'cmppStatus',
title: '客户连接状态',
width: '250px',
render: (record) => (
<div className="cmpp-status-cell">
<Tag tone={record.cmppStatus === 'connected' ? 'success' : record.cmppStatus === 'disconnected' ? 'danger' : 'neutral'}>
{record.cmppStatus === 'connected' ? '已连接' : record.cmppStatus === 'disconnected' ? '已断开' : '未开通'}
</Tag>
<button disabled={!record.cmppParams.interfaceEnabled} onClick={() => onOpenConnection(record)} type="button">
{record.cmppConnections.filter((item) => item.state === 'open').length}
</button>
<button
className={`cmpp-status-cell__params ${record.cmppParams.interfaceEnabled ? 'is-enabled' : 'is-disabled'}`}
disabled={!record.cmppParams.interfaceEnabled}
onClick={() => onOpenCmppParams(record)}
type="button"
>
<Settings2 size={13} />
CMPP参数
</button>
<button
className={`cmpp-status-cell__params ${record.httpEnabled ? 'is-enabled' : 'is-disabled'}`}
disabled={!record.httpEnabled}
onClick={() => onOpenHttpParams(record)}
type="button"
>
HTTP参数
</button>
</div>
),
},
{ key: 'enabled', title: '状态', width: '130px', render: applicationStatusTag },
{
key: 'actions',
title: '操作',
align: 'right',
width: '190px',
render: (record) => (
<div className="table-actions enterprise-app-actions">
<Button icon={<Edit3 size={15} />} onClick={() => onEdit(record)} size="sm" variant="ghost">编辑</Button>
<Button
onClick={() => {
if (record.status === 'active') onOpenDeactivate(record);
else onConfirmAction({ action: 'enable', id: record.id, name: record.name });
}}
size="sm"
variant={record.status === 'active' ? 'warning' : 'success'}
>
{record.status === 'active' ? '停用' : '启用'}
</Button>
<Button
icon={<Trash2 size={15} />}
onClick={() => onConfirmAction({ action: 'delete', id: record.id, name: record.name })}
size="sm"
variant="danger"
>
删除
</Button>
</div>
),
},
], [
onConfirmAction,
onEdit,
onOpenCmppParams,
onOpenConnection,
onOpenDeactivate,
onOpenHttpParams,
]);
return (
<div className="surface section-stack">
<Tabs
items={[
{
label: '短信应用',
value: 'sms',
content: (
<>
<Table columns={columns} data={apps} pagination={false} rowKey="id" />
<Pagination
nextDisabled={page >= totalPages}
onNext={() => onPageChange(Math.min(totalPages, page + 1))}
onPageChange={onPageChange}
onPrevious={() => onPageChange(Math.max(1, page - 1))}
page={page}
previousDisabled={page <= 1}
total={total}
totalPages={totalPages}
/>
</>
),
},
{
label: '彩信应用',
value: 'mms',
pending: true,
content: <div className="ui-table__empty">彩信应用待后端能力确认,本页不展示演示数据。</div>,
},
]}
/>
</div>
);
}