import { useEffect, useMemo, useState } from 'react'; import { Copy, Edit3, Plus, Search, Settings2, Trash2 } from 'lucide-react'; import { useNavigate } from 'react-router-dom'; import { Breadcrumb, Button, Input, Modal, Select, Table, Tabs, Tag, type TableColumn } from '@/components/ui'; import { adminApi, type ApplicationCmppParams, type CmppConnectionState, type EnterpriseApplication, type TenantOption } from '@/api/adminApi'; import { formatDateTime } from '@/utils/dateTime'; type SmsApp = { id: string; tenantId: string; name: string; enterprise: string; appId: string; enabled: boolean; sentToday: number; deliveryRate: number; unitPrice: number; cmppStatus: 'connected' | 'disconnected' | 'inactive'; cmppConnections: CmppConnection[]; cmppParams: CmppParams; }; type CmppParams = { host: string; port: number; interfaceEnabled: boolean; interfaceType: string; enterpriseCode: string; account: string; password: string; accessNumber: string; maxConnections: number; heartbeatSeconds: number; windowSize: number; protocolVersion: string; }; type CmppConnection = { id: string; state: 'open' | 'closed' | 'reconnecting'; bindType: 'transceiver' | 'submitter' | 'receiver'; clientIp: string; sourceAddr: string; establishedAt: string; lastHeartbeatAt: string; lastSubmitAt: string; pendingWindow: number; }; function enabledTag(enabled: boolean) { return {enabled ? '启用' : '停用'}; } function ConfirmModal({ message, danger, onCancel, onConfirm }: { message: string; danger?: boolean; onCancel: () => void; onConfirm: () => void }) { return ( )} onClose={onCancel} open title="操作确认" >

{message}

); } function AddApplicationModal({ tenants, loading, selectedTenantId, onChange, onCancel, onConfirm, }: { tenants: TenantOption[]; loading: boolean; selectedTenantId: string; onChange: (tenantId: string) => void; onCancel: () => void; onConfirm: () => void; }) { return ( )} onClose={onCancel} open title={

新建企业应用

先选择真实企业,再配置短信应用和三网通道组。

} >
setEnterpriseKeyword(event.target.value)} placeholder="请输入企业名称" prefix={} value={enterpriseKeyword} />
{error ?
{error}
: null}
}, { label: '彩信应用', value: 'mms', pending: true, content:
彩信应用待后端能力确认,本页不展示演示数据。
}, ]} />
{confirmAction ? ( setConfirmAction(null)} onConfirm={() => { void runConfirmedAction(); }} /> ) : null} {addModalOpen ? ( setAddModalOpen(false)} onChange={setSelectedTenantId} onConfirm={confirmAddApplication} selectedTenantId={selectedTenantId} tenants={tenants} /> ) : null} {connectionApp ? ( setConnectionApp(null)} onDeleteConnection={(connectionId) => { void deleteConnection(connectionApp.id, connectionId); }} /> ) : null} {paramsApp ? { setParamsApp(null); setParamsDetail(null); }} /> : null} ); } function mapApplication(application: EnterpriseApplication): SmsApp { const connections = (application.cmppConnections ?? []).map(mapConnection); return { id: application.id, tenantId: application.tenantId, name: application.name, enterprise: application.tenant?.name ?? application.tenantId, appId: application.id, enabled: application.status === 'active', sentToday: application.sentToday ?? 0, deliveryRate: application.deliveryRate ?? 0, unitPrice: (application.customerUnitPrice ?? 0) / 100, cmppStatus: application.interfaceEnabled === false ? 'inactive' : application.cmppStatus === 'connected' ? 'connected' : application.cmppStatus === 'inactive' ? 'inactive' : 'disconnected', cmppParams: { host: '', port: 0, interfaceEnabled: application.interfaceEnabled !== false, interfaceType: application.interfaceType ?? 'cmpp20', enterpriseCode: application.cmppEnterpriseCode ?? application.tenant?.code ?? application.tenantId, account: application.cmppAccount ?? application.tenantId, password: '', accessNumber: '', maxConnections: 0, heartbeatSeconds: 30, windowSize: 16, protocolVersion: 'CMPP2.0' }, cmppConnections: connections, }; } function mapConnection(connection: CmppConnectionState): CmppConnection { const isOpen = connection.status === 'connected' && connection.currentConnections > 0; return { id: connection.connectionId, state: isOpen ? 'open' : connection.status === 'reconnecting' ? 'reconnecting' : 'closed', bindType: 'transceiver', clientIp: String(connection.channel?.gatewayHost ?? ''), sourceAddr: String(connection.channel?.enterpriseCode ?? ''), establishedAt: formatDateTime(connection.lastConnectedAt), lastHeartbeatAt: formatDateTime(connection.lastHeartbeatAt), lastSubmitAt: formatDateTime(connection.updatedAt), pendingWindow: connection.currentConnections, }; }