import { useState } from 'react'; import { Button, Input, Modal, Select } from '@/components/ui'; import { isValidMoneyInput, moneyUnitsToYuan, yuanToMoneyUnits } from '@/utils/currency'; import { baseCarrierOptions, cmppVersionOptions, regionOptions } from './channelModel'; import type { BaseCarrier, ChannelModalState, LongMessageReceiptMode, SmsChannel } from './channelTypes'; export function ChannelFormModal({ modal, onClose, onSubmit, }: { modal: ChannelModalState; onClose: () => void; onSubmit: (channel: SmsChannel) => void; }) { const channel = modal.channel; const [name, setName] = useState(channel?.name ?? ''); const [carriers, setCarriers] = useState(channel?.carriers ?? ['mobile']); const [carrierError, setCarrierError] = useState(''); const [unitPrice, setUnitPrice] = useState(channel ? moneyUnitsToYuan(channel.unitPrice).toFixed(4) : '0.0300'); const [unitPriceError, setUnitPriceError] = useState(''); const [region, setRegion] = useState(channel?.sendRegion ?? '全国'); const [gatewayHost, setGatewayHost] = useState(channel?.gatewayHost ?? ''); const [gatewayPort, setGatewayPort] = useState(channel?.gatewayPort ?? '7890'); const [businessCode, setBusinessCode] = useState(channel?.businessCode ?? 'SMS'); const [corpCode, setCorpCode] = useState(channel?.corpCode ?? ''); const [account, setAccount] = useState(channel?.account ?? ''); const [cmppVersion, setCmppVersion] = useState<'2.0' | '3.0'>(channel?.cmppVersion ?? '2.0'); const [password, setPassword] = useState(''); const [accessNo, setAccessNo] = useState(channel?.accessNo ?? ''); const [extensionDigits, setExtensionDigits] = useState(String(channel?.extensionDigits ?? 0)); const [flowLimit, setFlowLimit] = useState(String(channel?.rateLimitPerSecond ?? 100)); const [desiredConnections, setDesiredConnections] = useState(String(channel?.desiredConnections ?? 1)); const [windowSize, setWindowSize] = useState(String(channel?.windowSize ?? 16)); const [heartbeatIntervalSeconds, setHeartbeatIntervalSeconds] = useState( String(channel?.heartbeatIntervalSeconds ?? 30), ); const [heartbeatMissThreshold, setHeartbeatMissThreshold] = useState(String(channel?.heartbeatMissThreshold ?? 3)); const [longMessageReceiptMode, setLongMessageReceiptMode] = useState( channel?.longMessageReceiptMode ?? 'per_segment', ); function submit() { if (carriers.length === 0) { setCarrierError('至少选择一个运营商'); return; } if (!isValidMoneyInput(unitPrice)) { setUnitPriceError('单价必须是非负金额,且最多保留小数点后 4 位'); return; } onSubmit({ id: channel?.id ?? String(Math.floor(10000 + Math.random() * 80000)), name: name || '新建短信通道', carrier: carriers.length === 3 ? 'all' : carriers[0], carriers, sendRegion: region, unitPrice: yuanToMoneyUnits(unitPrice), status: channel?.status ?? 'connecting', total: channel?.total ?? 0, submitFailureRate: channel?.submitFailureRate ?? 0, submitFailureCount: channel?.submitFailureCount ?? 0, successRate: channel?.successRate ?? 0, successCount: channel?.successCount ?? 0, unknownRate: channel?.unknownRate ?? 0, unknownCount: channel?.unknownCount ?? 0, failureRate: channel?.failureRate ?? 0, failureCount: channel?.failureCount ?? 0, gatewayHost, gatewayPort, businessCode: businessCode.trim() || 'SMS', corpCode, account, accessNo, cmppVersion, desiredConnections: Number(desiredConnections) || 1, windowSize: Number(windowSize) || 16, heartbeatIntervalSeconds: Number(heartbeatIntervalSeconds) || 30, heartbeatMissThreshold: Number(heartbeatMissThreshold) || 3, extensionDigits: Number(extensionDigits), longMessageReceiptMode, rateLimitPerSecond: Number(flowLimit), passwordCipher: password || undefined, }); } return ( } onClose={onClose} open size="xl" title={

{modal.mode === 'edit' ? '编辑通道' : '创建通道'}

} >

业务信息

setName(event.target.value)} placeholder="请输入通道名称" value={name} />
* 运营商 {baseCarrierOptions.map((item) => ( ))} {carrierError ? {carrierError} : null}
{ setUnitPrice(event.target.value); setUnitPriceError(''); }} step="0.0001" type="number" value={unitPrice} />
setGatewayHost(event.target.value)} placeholder="请输入网关地址" value={gatewayHost} /> setGatewayPort(event.target.value)} value={gatewayPort} />
setBusinessCode(event.target.value.toUpperCase())} value={businessCode} /> setCorpCode(event.target.value)} placeholder="请输入企业代码" value={corpCode} /> setAccount(event.target.value)} placeholder="请输入网关账号" value={account} /> setPassword(event.target.value)} placeholder={modal.mode === 'edit' ? '留空不修改' : '请输入网关密码'} required={modal.mode === 'create'} type="password" value={password} />
setAccessNo(event.target.value)} placeholder="请输入通道接入号" value={accessNo} /> setExtensionDigits(event.target.value)} type="number" value={extensionDigits} />
setFlowLimit(event.target.value)} suffix="条/秒" type="number" value={flowLimit} /> setDesiredConnections(event.target.value)} placeholder="1" value={desiredConnections} /> setWindowSize(event.target.value)} placeholder="16" value={windowSize} /> setHeartbeatIntervalSeconds(event.target.value)} suffix="秒" type="number" value={heartbeatIntervalSeconds} /> setHeartbeatMissThreshold(event.target.value)} suffix="次" type="number" value={heartbeatMissThreshold} />