fix: connect operations pages to real backend

This commit is contained in:
hectorzhao
2026-07-02 15:16:34 +08:00
parent ab421cf8a7
commit 321cf716f2
22 changed files with 1255 additions and 429 deletions
+184
View File
@@ -2,6 +2,8 @@ type RequestOptions = RequestInit & {
tenantId?: string;
};
export const DEFAULT_CLIENT_TENANT_ID = 'tenant-a';
async function request<T>(path: string, options: RequestOptions = {}): Promise<T> {
const headers = new Headers(options.headers);
headers.set('Content-Type', 'application/json');
@@ -74,7 +76,178 @@ export type SmsTemplateAudit = {
tenant?: { name: string };
};
export type TenantOption = {
id: string;
name: string;
code: string;
status: string;
};
export type DashboardResponse = {
taskCount: number;
messageStatus: Array<{ status: string; _count: { _all: number }; _sum: { amountCents?: number | null; billingUnits?: number | null } }>;
today: { sent: number; delivered: number; failed: number; unknown: number; successRate: number; spendCents: number; billingUnits: number };
uplinkCount: number;
billing: { _count: { _all: number }; _sum: { amountCents?: number | null; billingUnits?: number | null } };
transactions: { _count: { _all: number }; _sum: { amountCents?: number | null; smsUnits?: number | null } };
gatewayConnections: Array<{ status: string; _count: { _all: number }; _sum: { currentConnections?: number | null; desiredConnections?: number | null } }>;
pendingAuditCount: number;
accounts: Array<{ id: string; tenantId: string; balanceCents: number; smsUnits: number; creditCents: number; status: string; tenant?: TenantOption }>;
recentTasks: Array<Record<string, unknown>>;
recentRecharges: Array<RechargeOrder>;
};
export type RechargeOrder = {
id: string;
tenantId: string;
orderNo: string;
amountCents: number;
smsUnits: number;
status: string;
payMethod?: string | null;
paidAt?: string | null;
operatorId?: string | null;
remark?: string | null;
createdAt: string;
tenant?: TenantOption;
};
export type AccountTransaction = {
id: string;
tenantId: string;
transactionType: string;
amountCents: number;
smsUnits: number;
balanceAfter: number;
relatedType?: string | null;
relatedId?: string | null;
remark?: string | null;
createdAt: string;
};
export type TenantAccount = {
id: string;
tenantId: string;
balanceCents: number;
smsUnits: number;
creditCents: number;
status: string;
tenant?: TenantOption;
};
export type OperationLogItem = {
id: string;
time: string;
level: 'info' | 'success' | 'warning' | 'error';
tenant: string;
module: string;
operator: string;
action: string;
resourceId: string;
detail: Record<string, unknown>;
ip: string;
userAgent: string;
};
export type OperationLogResponse = {
items: OperationLogItem[];
total: number;
page: number;
pageSize: number;
modules: string[];
};
export type EnterpriseApplication = {
id: string;
tenantId: string;
name: string;
scene?: string | null;
status: string;
dailyLimit?: number | null;
tenant?: TenantOption;
sentToday?: number;
deliveryRate?: number;
cmppStatus?: 'connected' | 'degraded' | 'disconnected' | 'inactive';
cmppConnections?: CmppConnectionState[];
};
export type CmppConnectionState = {
id: string;
tenantId?: string | null;
channelId: string;
connectionId: string;
status: string;
desiredConnections: number;
currentConnections: number;
lastConnectedAt?: string | null;
lastDisconnectedAt?: string | null;
lastHeartbeatAt?: string | null;
reconnectCount: number;
lastError?: string | null;
updatedAt: string;
channel?: AdminChannel;
};
export type ApplicationConnectionsResponse = {
application: EnterpriseApplication;
connections: CmppConnectionState[];
summary: { desiredConnections: number; currentConnections: number; status: string };
};
export type ApplicationCmppParams = {
applicationId: string;
applicationName: string;
tenantName: string;
appCode: string;
gatewayHost: string;
gatewayPort: number;
enterpriseCode: string;
account: string;
passwordCipher: string;
srcId: string;
maxConnections: number;
heartbeatSeconds: number;
windowSize: number;
protocolVersion: string;
};
function withQuery(path: string, query: Record<string, string | number | undefined>) {
const params = new URLSearchParams();
Object.entries(query).forEach(([key, value]) => {
if (value !== undefined && value !== '' && value !== 'all') {
params.set(key, String(value));
}
});
const suffix = params.toString() ? `?${params}` : '';
return `${path}${suffix}`;
}
export const adminApi = {
listTenants: () => request<TenantOption[]>('/admin/tenants'),
getDashboard: (tenantId?: string) => request<DashboardResponse>(withQuery('/admin/operations/dashboard/statistics', { tenantId })),
listSystemLogs: (query: { tenantId?: string; keyword?: string; level?: string; module?: string; range?: string; page?: number; pageSize?: number }) =>
request<OperationLogResponse>(withQuery('/admin/system-logs', query)),
listAccounts: () => request<TenantAccount[]>('/admin/billing/accounts'),
listTransactions: (tenantId?: string) => request<AccountTransaction[]>(withQuery('/admin/billing/transactions', { tenantId })),
listManualRecharges: (tenantId?: string) => request<RechargeOrder[]>(withQuery('/admin/billing/manual-recharges', { tenantId })),
createManualRecharge: (body: { tenantId: string; amountCents: number; smsUnits?: number; operatorId?: string; remark?: string }) =>
request<RechargeOrder>('/admin/billing/manual-recharges', { method: 'POST', body: JSON.stringify(body) }),
listEnterpriseApplications: (query: { tenantId?: string; keyword?: string } = {}) =>
request<EnterpriseApplication[]>(withQuery('/admin/enterprise-applications', query)),
changeApplicationStatus: (id: string, status: string, reason?: string) =>
request<EnterpriseApplication>(`/admin/enterprise-applications/${id}/status`, {
method: 'POST',
body: JSON.stringify({ status, reason }),
}),
listApplicationConnections: (applicationId: string) =>
request<ApplicationConnectionsResponse>(`/admin/enterprise-applications/${applicationId}/connections`),
disconnectApplicationConnection: (applicationId: string, connectionId: string, reason?: string) =>
request<CmppConnectionState>(`/admin/enterprise-applications/${applicationId}/connections/${connectionId}`, {
method: 'DELETE',
body: JSON.stringify({ reason }),
}),
getApplicationCmppParams: (applicationId: string) =>
request<ApplicationCmppParams>(`/admin/enterprise-applications/${applicationId}/cmpp-params`),
listChannels: () => request<AdminChannel[]>('/admin/channels'),
copyChannel: (id: string, body: { operatorId?: string } = {}) => request<AdminChannel>(`/admin/channels/${id}/copy`, {
method: 'POST',
@@ -118,3 +291,14 @@ export const adminApi = {
body: JSON.stringify({ reason }),
}),
};
export const clientApi = {
getDashboard: (tenantId = DEFAULT_CLIENT_TENANT_ID) =>
request<DashboardResponse>('/client/operations/dashboard', { tenantId }),
listSystemLogs: (query: { keyword?: string; level?: string; module?: string; range?: string; page?: number; pageSize?: number }, tenantId = DEFAULT_CLIENT_TENANT_ID) =>
request<OperationLogResponse>(withQuery('/client/operations/system-logs', query), { tenantId }),
listTransactions: (tenantId = DEFAULT_CLIENT_TENANT_ID) =>
request<AccountTransaction[]>('/client/billing/transactions', { tenantId }),
listOrders: (tenantId = DEFAULT_CLIENT_TENANT_ID) =>
request<RechargeOrder[]>('/client/billing/orders', { tenantId }),
};