feat: add access number routing and admin list improvements

This commit is contained in:
hectorzhao
2026-07-15 15:45:27 +08:00
parent 27c464246b
commit 3e114ee729
19 changed files with 547 additions and 508 deletions
@@ -24,6 +24,9 @@ export function AdminSmsApplicationFormPage() {
const [customerUnitPrice, setCustomerUnitPrice] = useState('0.0300');
const [queuePriority, setQueuePriority] = useState<QueuePriority>('normal');
const [cmppAccount, setCmppAccount] = useState('');
const [applicationExtension, setApplicationExtension] = useState('');
const [accessNumberFillEnabled, setAccessNumberFillEnabled] = useState(false);
const [accessNumberFillPrefix, setAccessNumberFillPrefix] = useState('');
const [passwordCipher, setPasswordCipher] = useState(() => generateApplicationPassword());
const [interfaceEnabled, setInterfaceEnabled] = useState(true);
const [interfaceType, setInterfaceType] = useState<InterfaceType>('cmpp20');
@@ -84,6 +87,9 @@ export function AdminSmsApplicationFormPage() {
setCustomerUnitPrice(((application.customerUnitPrice ?? 0) / 100).toFixed(3));
setQueuePriority(application.queuePriority === 'priority' ? 'priority' : 'normal');
setCmppAccount(application.cmppAccount ?? '');
setApplicationExtension(application.cmppApplicationExtension ?? '');
setAccessNumberFillEnabled(application.cmppAccessNumberFillEnabled === true);
setAccessNumberFillPrefix(application.cmppAccessNumberFillPrefix ?? '');
setPasswordCipher('');
setInterfaceEnabled(application.interfaceEnabled !== false);
setInterfaceType('cmpp20');
@@ -119,6 +125,24 @@ export function AdminSmsApplicationFormPage() {
setError('请至少配置一个运营商通道组');
return;
}
const normalizedExtension = applicationExtension.trim();
const normalizedFillPrefix = accessNumberFillPrefix.trim();
if (normalizedExtension && !/^\d+$/.test(normalizedExtension)) {
setError('应用扩展码只能填写数字');
return;
}
if (accessNumberFillEnabled && !normalizedExtension) {
setError('开启接入号填充时必须填写应用扩展码');
return;
}
if (accessNumberFillEnabled && !/^\d+$/.test(normalizedFillPrefix)) {
setError('开启接入号填充时必须填写数字格式的填充前缀');
return;
}
if (`${accessNumberFillEnabled ? normalizedFillPrefix : ''}${normalizedExtension}`.length > 21) {
setError('客户侧接入号不能超过 21 位');
return;
}
const payload = {
name: appName,
scene,
@@ -126,6 +150,9 @@ export function AdminSmsApplicationFormPage() {
customerUnitPrice: Math.round(Number(customerUnitPrice || 0) * 100),
queuePriority,
cmppAccount: cmppAccount.trim() || undefined,
cmppApplicationExtension: normalizedExtension,
cmppAccessNumberFillEnabled: accessNumberFillEnabled,
cmppAccessNumberFillPrefix: accessNumberFillEnabled ? normalizedFillPrefix : '',
passwordCipher: passwordCipher.trim() || undefined,
interfaceEnabled,
interfaceType,
@@ -164,6 +191,7 @@ export function AdminSmsApplicationFormPage() {
...groups.filter((group) => group.carrier === carrier).map((group) => ({ label: group.name, value: group.id })),
];
const selectedGroupCount = [mobileGroupId, unicomGroupId, telecomGroupId].filter(Boolean).length;
const clientSrcIdPreview = `${accessNumberFillEnabled ? accessNumberFillPrefix.trim() : ''}${applicationExtension.trim()}`;
const routeCards: Array<{ carrier: Carrier; groupId: string; onChange: (value: string) => void }> = [
{ carrier: 'mobile', groupId: mobileGroupId, onChange: setMobileGroupId },
{ carrier: 'unicom', groupId: unicomGroupId, onChange: setUnicomGroupId },
@@ -249,6 +277,35 @@ export function AdminSmsApplicationFormPage() {
</div>
<Input label="CMPP 6位账号" onChange={(event) => setCmppAccount(event.target.value)} placeholder="留空自动生成" value={cmppAccount} />
<Input disabled hint="企业代码始终与 CMPP 6位账号一致;账号留空自动生成时,保存后自动生成相同企业代码。" label="企业代码" placeholder="跟随 CMPP 6位账号自动生成" value={cmppAccount} />
<Input
hint="真实扩展码会追加到上游通道基础接入号后,例如基础号 1069999999、扩展码 0001,最终发送号为 10699999990001。留空则继续使用通道基础号。"
label="应用扩展码"
onChange={(event) => setApplicationExtension(event.target.value)}
placeholder="例如 0001"
value={applicationExtension}
/>
<div className="admin-app-form-row admin-app-form-row--wide">
<span></span>
<button className={accessNumberFillEnabled ? 'admin-switch is-on' : 'admin-switch'} onClick={() => setAccessNumberFillEnabled((current) => !current)} type="button">
<span />
{accessNumberFillEnabled ? '开启' : '关闭'}
</button>
<div className="admin-app-form-tip">
<Info size={17} />
<span> Src_Id </span>
</div>
</div>
{accessNumberFillEnabled ? (
<Input
hint="只能填写数字,且只允许作为客户 Src_Id 的开头前缀。"
label="填充前缀"
onChange={(event) => setAccessNumberFillPrefix(event.target.value)}
placeholder="例如 00"
required
value={accessNumberFillPrefix}
/>
) : null}
<Input disabled hint="客户 CMPP SUBMIT 必须填写该完整值;填充前缀不会发送给上游。" label="客户侧接入号" placeholder="根据填充前缀和应用扩展码自动生成" value={clientSrcIdPreview} />
<Input
hint={isEdit ? '留空则不修改接口密码;填写 16 位字符后覆盖。' : '默认随机生成,可按需修改。'}
label="接口密码"