fix: correct application cmpp credentials

This commit is contained in:
hectorzhao
2026-07-09 17:18:39 +08:00
parent 57a4c86a79
commit 767f0ca9aa
13 changed files with 149 additions and 24 deletions
+3 -2
View File
@@ -605,6 +605,7 @@ export type EnterpriseApplication = {
maxPhonesPerTask?: number | null;
templateMismatchMode?: string | null;
cmppAccount?: string | null;
cmppEnterpriseCode?: string | null;
cmppMaxConnections?: number | null;
cmppWindowSize?: number | null;
ipAllowlist?: Array<{ id: string; ipCidr: string; remark?: string | null }>;
@@ -801,9 +802,9 @@ export const adminApi = {
request<EnterpriseApplication[]>(withQuery('/admin/enterprise-applications', query)),
getEnterpriseApplication: (id: string) =>
request<EnterpriseApplication>(`/admin/enterprise-applications/${id}`),
createEnterpriseApplication: (body: { tenantId: string; name: string; scene?: string; dailyLimit?: number; customerUnitPrice?: number; queuePriority?: 'normal' | 'priority'; maxPhonesPerTask?: number; templateMismatchMode?: string; cmppAccount?: string; cmppMaxConnections?: number; cmppWindowSize?: number; ipAllowlist?: string[] }) =>
createEnterpriseApplication: (body: { tenantId: string; name: string; scene?: string; dailyLimit?: number; customerUnitPrice?: number; queuePriority?: 'normal' | 'priority'; maxPhonesPerTask?: number; templateMismatchMode?: string; cmppAccount?: string; cmppEnterpriseCode?: string; passwordCipher?: string; cmppMaxConnections?: number; cmppWindowSize?: number; ipAllowlist?: string[] }) =>
request<EnterpriseApplication>('/admin/enterprise-applications', { method: 'POST', body: JSON.stringify(body) }),
updateEnterpriseApplication: (id: string, body: { name?: string; scene?: string; dailyLimit?: number; customerUnitPrice?: number; queuePriority?: 'normal' | 'priority'; maxPhonesPerTask?: number; templateMismatchMode?: string; cmppAccount?: string; cmppMaxConnections?: number; cmppWindowSize?: number; ipAllowlist?: string[] }) =>
updateEnterpriseApplication: (id: string, body: { name?: string; scene?: string; dailyLimit?: number; customerUnitPrice?: number; queuePriority?: 'normal' | 'priority'; maxPhonesPerTask?: number; templateMismatchMode?: string; cmppAccount?: string; cmppEnterpriseCode?: string; passwordCipher?: string; cmppMaxConnections?: number; cmppWindowSize?: number; ipAllowlist?: string[] }) =>
request<EnterpriseApplication>(`/admin/enterprise-applications/${id}`, { method: 'PUT', body: JSON.stringify(body) }),
changeApplicationStatus: (id: string, status: string, reason?: string) =>
request<EnterpriseApplication>(`/admin/enterprise-applications/${id}/status`, {
+2 -2
View File
@@ -127,8 +127,8 @@ export function AdminCustomersPage({ basePath = '/admin/customers' }: AdminCusto
async function submitRecharge() {
if (!rechargeTarget) return;
const amount = Number(rechargeForm.amount);
if (!Number.isFinite(amount) || amount <= 0) {
setRechargeError('请填写大于 0 的充值金额');
if (!Number.isFinite(amount) || amount === 0) {
setRechargeError('请填写 0 的充值金额,支持负数冲正');
return;
}
setRecharging(true);
@@ -458,7 +458,7 @@ function mapApplication(application: EnterpriseApplication): SmsApp {
deliveryRate: application.deliveryRate ?? 0,
unitPrice: (application.customerUnitPrice ?? 0) / 100,
cmppStatus: application.cmppStatus === 'connected' ? 'connected' : application.cmppStatus === 'inactive' ? 'inactive' : 'disconnected',
cmppParams: { host: '', port: 0, enterpriseCode: application.tenant?.code ?? application.tenantId, account: application.tenant?.code ?? application.tenantId, password: '', accessNumber: '', maxConnections: 0, heartbeatSeconds: 30, windowSize: 16, protocolVersion: 'CMPP 3.0' },
cmppParams: { host: '', port: 0, enterpriseCode: application.cmppEnterpriseCode ?? application.tenant?.code ?? application.tenantId, account: application.cmppAccount ?? application.tenantId, password: '', accessNumber: '', maxConnections: 0, heartbeatSeconds: 30, windowSize: 16, protocolVersion: 'CMPP 3.0' },
cmppConnections: connections,
};
}
+1 -1
View File
@@ -103,7 +103,7 @@ export function AdminRechargeRecordsPage() {
async function submitManualRecharge() {
const amount = Number(form.amount);
const smsUnits = Number(form.smsUnits || 0);
if (!form.tenantId || !Number.isFinite(amount) || amount <= 0 || !Number.isFinite(smsUnits) || smsUnits < 0) {
if (!form.tenantId || !Number.isFinite(amount) || !Number.isFinite(smsUnits) || (amount === 0 && smsUnits === 0)) {
return;
}
await adminApi.createManualRecharge({
+23 -1
View File
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { ArrowLeft, Info, RadioTower } from 'lucide-react';
import { ArrowLeft, Info, RadioTower, RefreshCw } from 'lucide-react';
import { adminApi, type ChannelGroup, type DictionaryItem, type EnterpriseApplication } from '@/api/adminApi';
import { Breadcrumb, Button, Input, Select, Tag } from '@/components/ui';
@@ -23,6 +23,8 @@ export function AdminSmsApplicationFormPage() {
const [customerUnitPrice, setCustomerUnitPrice] = useState('0.0300');
const [queuePriority, setQueuePriority] = useState<QueuePriority>('normal');
const [cmppAccount, setCmppAccount] = useState('');
const [cmppEnterpriseCode, setCmppEnterpriseCode] = useState('');
const [passwordCipher, setPasswordCipher] = useState(() => generateApplicationPassword());
const [cmppMaxConnections, setCmppMaxConnections] = useState('1');
const [cmppWindowSize, setCmppWindowSize] = useState('16');
const [phoneDailyLimit, setPhoneDailyLimit] = useState('10');
@@ -79,6 +81,8 @@ export function AdminSmsApplicationFormPage() {
setCustomerUnitPrice(((application.customerUnitPrice ?? 0) / 100).toFixed(4));
setQueuePriority(application.queuePriority === 'priority' ? 'priority' : 'normal');
setCmppAccount(application.cmppAccount ?? '');
setCmppEnterpriseCode(application.cmppEnterpriseCode ?? application.tenant?.code ?? '');
setPasswordCipher('');
setCmppMaxConnections(String(application.cmppMaxConnections ?? 1));
setCmppWindowSize(String(application.cmppWindowSize ?? 16));
setPhoneDailyLimit(application.maxPhonesPerTask ? String(application.maxPhonesPerTask) : '');
@@ -117,6 +121,8 @@ export function AdminSmsApplicationFormPage() {
customerUnitPrice: Math.round(Number(customerUnitPrice || 0) * 100),
queuePriority,
cmppAccount: cmppAccount.trim() || undefined,
cmppEnterpriseCode: cmppEnterpriseCode.trim() || undefined,
passwordCipher: passwordCipher.trim() || undefined,
cmppMaxConnections: Number(cmppMaxConnections) || 1,
cmppWindowSize: Number(cmppWindowSize) || 16,
maxPhonesPerTask: Number(phoneDailyLimit) || undefined,
@@ -177,6 +183,15 @@ export function AdminSmsApplicationFormPage() {
<Input label="日发送数量限制" onChange={(event) => setDailyLimit(event.target.value)} placeholder="100000" required value={dailyLimit} />
<Input label="客户单价(元/条)" onChange={(event) => setCustomerUnitPrice(event.target.value)} placeholder="0.0300" required value={customerUnitPrice} />
<Input label="CMPP 6位账号" onChange={(event) => setCmppAccount(event.target.value)} placeholder="留空自动生成" value={cmppAccount} />
<Input label="企业代码" onChange={(event) => setCmppEnterpriseCode(event.target.value)} placeholder="请输入客户侧企业代码" value={cmppEnterpriseCode} />
<Input
hint={isEdit ? '留空则不修改接口密码;填写 16 位字符后覆盖。' : '默认随机生成,可按需修改。'}
label="接口密码"
onChange={(event) => setPasswordCipher(event.target.value)}
placeholder="16 位接口密码"
suffix={<button aria-label="随机生成接口密码" className="icon-button" onClick={() => setPasswordCipher(generateApplicationPassword())} type="button"><RefreshCw size={15} /></button>}
value={passwordCipher}
/>
<Input label="客户最大连接数" onChange={(event) => setCmppMaxConnections(event.target.value)} placeholder="1" required value={cmppMaxConnections} />
<Input label="客户提交窗口" onChange={(event) => setCmppWindowSize(event.target.value)} placeholder="16" required value={cmppWindowSize} />
<div className="admin-app-form-row admin-app-form-row--wide">
@@ -267,3 +282,10 @@ function parseIpAllowlist(value: string) {
.map((item) => item.trim())
.filter(Boolean);
}
function generateApplicationPassword() {
if (typeof crypto !== 'undefined' && 'randomUUID' in crypto) {
return crypto.randomUUID().replace(/-/g, '').slice(0, 16);
}
return Array.from({ length: 16 }, () => Math.floor(Math.random() * 16).toString(16)).join('');
}