Files
lislgosms/src/api/admin/governance.api.ts
T

504 lines
21 KiB
TypeScript

import { request, withQuery } from '../core/httpClient';
import type {
AdministrativeRegion,
AuditRecord,
ClientSmsSignature,
ClientSmsTemplate,
CommonReportField,
DictionaryItem,
DrainageDetectionResult,
DrainageDetectionRule,
EnterpriseCertification,
ManualRechargePreflight,
ManualRechargeResult,
PagedResult,
PhoneFrequencyHit,
PhoneFrequencyWhitelistItem,
RechargeOrder,
ReviewDecisionResult,
ReviewPreflight,
RiskReviewTask,
RiskRuleItem,
RiskTaskMessagePage,
SmsDrainageInfo,
SmsTemplateAudit,
TenantAccount,
} from '../types';
// Review, risk and billing mutations keep their original URLs, payloads and
// response types behind one governance boundary.
export const adminGovernanceApi = {
listAdministrativeRegions: () => request<AdministrativeRegion[]>('/admin/dictionaries/administrative-regions'),
listAccounts: () => request<TenantAccount[]>('/admin/billing/accounts'),
updateCreditLimit: (tenantId: string, body: { creditCents: number; operatorId?: string; remark?: string }) =>
request<TenantAccount>(`/admin/billing/accounts/${tenantId}/credit-limit`, {
method: 'POST',
body: JSON.stringify(body),
}),
listManualRecharges: (tenantId?: string) =>
request<RechargeOrder[]>(withQuery('/admin/billing/manual-recharges', { tenantId })),
listManualRechargesPage: (query: {
enterpriseKeyword?: string;
createdAtFrom?: string;
createdAtTo?: string;
page: number;
pageSize: number;
}) => request<PagedResult<RechargeOrder>>(withQuery('/admin/billing/manual-recharges', query)),
preflightManualRecharge: (body: { tenantId: string; amountCents: number }) =>
request<ManualRechargePreflight>('/admin/billing/manual-recharges/preflight', {
method: 'POST',
body: JSON.stringify(body),
}),
createManualRecharge: (body: {
tenantId: string;
amountCents: number;
expectedAccountUpdatedAt: string;
idempotencyKey: string;
remark?: string;
}) =>
request<ManualRechargeResult>('/admin/billing/manual-recharges', { method: 'POST', body: JSON.stringify(body) }),
listTemplateAudits: (query: {
keyword?: string;
status?: string;
submittedAtFrom?: string;
submittedAtTo?: string;
}) => {
const params = new URLSearchParams();
if (query.keyword) params.set('keyword', query.keyword);
if (query.status && query.status !== 'all') params.set('status', query.status);
if (query.submittedAtFrom) params.set('submittedAtFrom', query.submittedAtFrom);
if (query.submittedAtTo) params.set('submittedAtTo', query.submittedAtTo);
const suffix = params.toString() ? `?${params}` : '';
return request<SmsTemplateAudit[]>(`/admin/enterprise-templates${suffix}`);
},
approveTemplate: (id: string) =>
request<SmsTemplateAudit>(`/admin/templates/${id}/approve`, { method: 'POST', body: JSON.stringify({}) }),
rejectTemplate: (id: string, reason = '运营审核驳回') =>
request<SmsTemplateAudit>(`/admin/templates/${id}/reject`, {
method: 'POST',
body: JSON.stringify({ reason }),
}),
approveSignature: (id: string) =>
request<ClientSmsSignature>(`/admin/signatures/${id}/approve`, { method: 'POST', body: JSON.stringify({}) }),
rejectSignature: (id: string, reason = '运营审核驳回') =>
request<ClientSmsSignature>(`/admin/signatures/${id}/reject`, {
method: 'POST',
body: JSON.stringify({ reason }),
}),
getReviewPreflight: (type: 'signature' | 'template', id: string) =>
request<ReviewPreflight>(`/admin/reviews/${type}/${id}/preflight`),
submitReviewDecision: (
type: 'signature' | 'template',
id: string,
body: { decision: 'approve' | 'reject'; expectedUpdatedAt: string; idempotencyKey: string; reason?: string },
) =>
request<ReviewDecisionResult>(`/admin/reviews/${type}/${id}/decision`, {
method: 'POST',
body: JSON.stringify(body),
}),
listEnterpriseSignatures: (
query: {
tenantId?: string;
keyword?: string;
status?: string;
enterpriseKeyword?: string;
applicationKeyword?: string;
signatureKeyword?: string;
drainageKeyword?: string;
submittedAtFrom?: string;
submittedAtTo?: string;
} = {},
) => request<ClientSmsSignature[]>(withQuery('/admin/enterprise-signatures', query)),
listEnterpriseSignaturesPage: (query: {
tenantId?: string;
keyword?: string;
status?: string;
enterpriseKeyword?: string;
applicationKeyword?: string;
signatureKeyword?: string;
drainageKeyword?: string;
page: number;
pageSize: number;
}) =>
request<PagedResult<ClientSmsSignature> & { pendingReportMaterialTotal: number; pendingReportDetailTotal: number }>(
withQuery('/admin/enterprise-signatures', query),
),
listEnterpriseSignatureOptions: (query: { tenantId?: string } = {}) =>
request<ClientSmsSignature[]>(withQuery('/admin/enterprise-signature-options', query)),
getEnterpriseSignature: (id: string) => request<ClientSmsSignature>(`/admin/enterprise-signatures/${id}`),
getEnterpriseSignatureReportTargets: (id: string) =>
request<NonNullable<ClientSmsSignature['reportTargets']>>(`/admin/enterprise-signatures/${id}/report-targets`),
getDrainageInfoReportTargets: (id: string) =>
request<NonNullable<ClientSmsSignature['drainageReportTargets']>[string]>(
`/admin/drainage-infos/${id}/report-targets`,
),
createEnterpriseSignature: (body: {
tenantId: string;
applicationId?: string;
name: string;
purpose?: string;
drainageInfo?: Record<string, unknown>;
}) => request<ClientSmsSignature>('/admin/enterprise-signatures', { method: 'POST', body: JSON.stringify(body) }),
updateEnterpriseSignature: (
id: string,
body: {
applicationId?: string | null;
name?: string;
purpose?: string;
auditStatus?: string;
drainageInfo?: Record<string, unknown>;
},
) => request<ClientSmsSignature>(`/admin/enterprise-signatures/${id}`, { method: 'PUT', body: JSON.stringify(body) }),
changeEnterpriseSignatureStatus: (id: string, status: string, reason?: string) =>
request<ClientSmsSignature>(`/admin/enterprise-signatures/${id}/status`, {
method: 'POST',
body: JSON.stringify({ status, reason }),
}),
listDrainageInfos: (
query: {
tenantId?: string;
signatureId?: string;
keyword?: string;
status?: string;
submittedAtFrom?: string;
submittedAtTo?: string;
} = {},
) => request<SmsDrainageInfo[]>(withQuery('/admin/drainage-infos', query)),
listAuditRecords: (query: { targetType?: string; targetId?: string } = {}) =>
request<AuditRecord[]>(withQuery('/admin/audit-records', query)),
createDrainageInfo: (
signatureId: string,
body: { url: string; remark?: string; reportValues?: Record<string, unknown> },
) =>
request<SmsDrainageInfo>(`/admin/enterprise-signatures/${signatureId}/drainage-infos`, {
method: 'POST',
body: JSON.stringify(body),
}),
updateDrainageInfo: (id: string, body: { url?: string; remark?: string; reportValues?: Record<string, unknown> }) =>
request<SmsDrainageInfo>(`/admin/drainage-infos/${id}`, { method: 'PUT', body: JSON.stringify(body) }),
approveDrainageInfo: (id: string) =>
request<SmsDrainageInfo>(`/admin/drainage-infos/${id}/approve`, { method: 'POST', body: JSON.stringify({}) }),
rejectDrainageInfo: (id: string, reason: string) =>
request<SmsDrainageInfo>(`/admin/drainage-infos/${id}/reject`, {
method: 'POST',
body: JSON.stringify({ reason }),
}),
changeDrainageInfoStatus: (id: string, status: string, reason?: string) =>
request<SmsDrainageInfo>(`/admin/drainage-infos/${id}/status`, {
method: 'POST',
body: JSON.stringify({ status, reason }),
}),
listEnterpriseTemplates: (
query: {
tenantId?: string;
keyword?: string;
status?: string;
enterpriseKeyword?: string;
applicationKeyword?: string;
nameKeyword?: string;
contentKeyword?: string;
} = {},
) => request<ClientSmsTemplate[]>(withQuery('/admin/enterprise-templates', query)),
listEnterpriseTemplatesPage: (query: {
tenantId?: string;
keyword?: string;
status?: string;
enterpriseKeyword?: string;
applicationKeyword?: string;
nameKeyword?: string;
contentKeyword?: string;
page: number;
pageSize: number;
}) => request<PagedResult<ClientSmsTemplate>>(withQuery('/admin/enterprise-templates', query)),
createEnterpriseTemplate: (body: {
tenantId: string;
applicationId: string;
signatureId?: string;
name: string;
content: string;
category?: string;
variables?: Array<{ name: string; example?: string; required?: boolean }>;
}) => request<ClientSmsTemplate>('/admin/enterprise-templates', { method: 'POST', body: JSON.stringify(body) }),
updateEnterpriseTemplate: (
id: string,
body: {
applicationId?: string;
signatureId?: string | null;
name?: string;
content?: string;
category?: string;
auditStatus?: string;
variables?: Array<{ name: string; example?: string; required?: boolean }>;
},
) => request<ClientSmsTemplate>(`/admin/enterprise-templates/${id}`, { method: 'PUT', body: JSON.stringify(body) }),
changeEnterpriseTemplateStatus: (id: string, status: string, reason?: string) =>
request<ClientSmsTemplate>(`/admin/enterprise-templates/${id}/status`, {
method: 'POST',
body: JSON.stringify({ status, reason }),
}),
getTemplateOptOutPolicy: (id: string) =>
request<{
rules: Array<{ channelId: string; action: 'add' | 'remove' }>;
preserveFragments: boolean;
channels: Array<{ id: string; name: string; groupNames: string[] }>;
}>(`/admin/enterprise-templates/${id}/opt-out-policy`),
updateTemplateOptOutPolicy: (
id: string,
body: { rules: Array<{ channelId: string; action: 'add' | 'remove' }>; preserveFragments: true },
) => request(`/admin/enterprise-templates/${id}/opt-out-policy`, { method: 'PUT', body: JSON.stringify(body) }),
listEnterpriseCertifications: (query: {
keyword?: string;
status?: string;
submittedAtFrom?: string;
submittedAtTo?: string;
}) => {
const params = new URLSearchParams();
if (query.keyword) params.set('keyword', query.keyword);
if (query.status && query.status !== 'all') params.set('status', query.status);
if (query.submittedAtFrom) params.set('submittedAtFrom', query.submittedAtFrom);
if (query.submittedAtTo) params.set('submittedAtTo', query.submittedAtTo);
const suffix = params.toString() ? `?${params}` : '';
return request<EnterpriseCertification[]>(`/admin/enterprise-certifications${suffix}`);
},
getEnterpriseCertification: (id: string) =>
request<EnterpriseCertification>(`/admin/enterprise-certifications/${id}`),
approveEnterpriseCertification: (id: string) =>
request<EnterpriseCertification>(`/admin/enterprise-certifications/${id}/approve`, {
method: 'POST',
body: JSON.stringify({}),
}),
rejectEnterpriseCertification: (id: string, reason = '运营审核驳回') =>
request<EnterpriseCertification>(`/admin/enterprise-certifications/${id}/reject`, {
method: 'POST',
body: JSON.stringify({ reason }),
}),
listRiskReviewTasks: (
query: { tenantId?: string; status?: string; submittedAtFrom?: string; submittedAtTo?: string } = {},
) => request<RiskReviewTask[]>(withQuery('/admin/risk-review/tasks', query)),
listRiskRules: (applicationId?: string) =>
request<RiskRuleItem[]>(withQuery('/admin/risk-review/rules', { applicationId })),
createRiskRule: (body: {
applicationId?: string;
code: RiskRuleItem['code'];
thresholdValue: number;
action: RiskRuleItem['action'];
status: RiskRuleItem['status'];
priority?: number;
config?: RiskRuleItem['config'];
}) => request<RiskRuleItem>('/admin/risk-review/rules', { method: 'POST', body: JSON.stringify(body) }),
updateRiskRule: (
id: string,
body: {
thresholdValue?: number;
action?: RiskRuleItem['action'];
status?: RiskRuleItem['status'];
priority?: number;
config?: RiskRuleItem['config'];
},
) => request<RiskRuleItem>(`/admin/risk-review/rules/${id}`, { method: 'PUT', body: JSON.stringify(body) }),
listPhoneFrequencyHits: (
query: {
tenantId?: string;
applicationId?: string;
phoneNumber?: string;
status?: 'active' | 'expired' | 'released';
createdAtFrom?: string;
createdAtTo?: string;
page?: number;
pageSize?: number;
} = {},
) => request<PagedResult<PhoneFrequencyHit>>(withQuery('/admin/risk-review/phone-frequency-hits', query)),
releasePhoneFrequencyHit: (id: string, reason: string) =>
request<PhoneFrequencyHit>(`/admin/risk-review/phone-frequency-hits/${id}/release`, {
method: 'POST',
body: JSON.stringify({ reason }),
}),
listPhoneFrequencyWhitelist: (
query: {
phoneNumber?: string;
keyword?: string;
status?: 'active' | 'inactive' | 'deleted';
updatedAtFrom?: string;
updatedAtTo?: string;
page?: number;
pageSize?: number;
} = {},
) =>
request<PagedResult<PhoneFrequencyWhitelistItem>>(withQuery('/admin/risk-review/phone-frequency-whitelist', query)),
createPhoneFrequencyWhitelist: (body: {
phoneNumber: string;
reason: string;
remark?: string;
status?: 'active' | 'inactive';
}) =>
request<PhoneFrequencyWhitelistItem>('/admin/risk-review/phone-frequency-whitelist', {
method: 'POST',
body: JSON.stringify(body),
}),
updatePhoneFrequencyWhitelist: (
id: string,
body: {
phoneNumber?: string;
reason?: string;
remark?: string;
status?: 'active' | 'inactive';
},
) =>
request<PhoneFrequencyWhitelistItem>(`/admin/risk-review/phone-frequency-whitelist/${id}`, {
method: 'PUT',
body: JSON.stringify(body),
}),
deletePhoneFrequencyWhitelist: (id: string, reason: string) =>
request<PhoneFrequencyWhitelistItem>(`/admin/risk-review/phone-frequency-whitelist/${id}`, {
method: 'DELETE',
body: JSON.stringify({ reason }),
}),
listRiskReviewTaskMessages: (id: string, query: { phone?: string; page?: number; pageSize?: number } = {}) =>
request<RiskTaskMessagePage>(withQuery(`/admin/risk-review/tasks/${id}/messages`, query)),
approveRiskReviewTask: (id: string, reason?: string) =>
request<RiskReviewTask>(`/admin/risk-review/tasks/${id}/approve`, {
method: 'POST',
body: JSON.stringify({ reason }),
}),
rejectRiskReviewTask: (id: string, reason?: string) =>
request<RiskReviewTask>(`/admin/risk-review/tasks/${id}/reject`, {
method: 'POST',
body: JSON.stringify({ reason }),
}),
rejectRiskReviewTasks: (ids: string[], reason: string) =>
request<RiskReviewTask[]>('/admin/risk-review/tasks/batch/reject', {
method: 'POST',
body: JSON.stringify({ ids, reason }),
}),
listSensitiveWords: (query: { keyword?: string; status?: string } = {}) =>
request<DictionaryItem[]>(withQuery('/admin/dictionaries/sensitive-words', query)),
createSensitiveWord: (body: { word: string; level?: string; status?: string }) =>
request<DictionaryItem>('/admin/dictionaries/sensitive-words', { method: 'POST', body: JSON.stringify(body) }),
deleteSensitiveWord: (id: string) =>
request<DictionaryItem>(`/admin/dictionaries/sensitive-words/${id}`, { method: 'DELETE' }),
listGlobalBlacklist: (query: { keyword?: string; status?: string } = {}) =>
request<DictionaryItem[]>(withQuery('/admin/dictionaries/blacklists/global', query)),
createGlobalBlacklist: (body: { phoneNumber: string; reason?: string; status?: string; operatorId?: string }) =>
request<DictionaryItem>('/admin/dictionaries/blacklists/global', { method: 'POST', body: JSON.stringify(body) }),
deleteGlobalBlacklist: (id: string) =>
request<DictionaryItem>(`/admin/dictionaries/blacklists/global/${id}`, { method: 'DELETE' }),
listEnterpriseBlacklist: (
query: {
tenantId?: string;
applicationId?: string;
keyword?: string;
status?: string;
enterpriseKeyword?: string;
applicationKeyword?: string;
phoneNumber?: string;
reasonKeyword?: string;
} = {},
) => request<DictionaryItem[]>(withQuery('/admin/dictionaries/blacklists/enterprise', query)),
createEnterpriseBlacklist: (body: {
tenantId: string;
applicationId: string;
phoneNumber: string;
reason?: string;
status?: string;
operatorId?: string;
}) =>
request<DictionaryItem>('/admin/dictionaries/blacklists/enterprise', {
method: 'POST',
body: JSON.stringify(body),
}),
deleteEnterpriseBlacklist: (id: string) =>
request<DictionaryItem>(`/admin/dictionaries/blacklists/enterprise/${id}`, { method: 'DELETE' }),
listPhoneSegments: (query: { keyword?: string; page?: number; pageSize?: number } = {}) =>
request<{ items: DictionaryItem[]; total: number; page: number; pageSize: number }>(
withQuery('/admin/dictionaries/phone-segments', query),
),
createPhoneSegment: (body: { prefix: string; carrier: string; province?: string; city?: string }) =>
request<DictionaryItem>('/admin/dictionaries/phone-segments', { method: 'POST', body: JSON.stringify(body) }),
deletePhoneSegment: (id: string) =>
request<DictionaryItem>(`/admin/dictionaries/phone-segments/${id}`, { method: 'DELETE' }),
listPhoneCarrierRules: (query: { keyword?: string; page?: number; pageSize?: number } = {}) =>
request<{ items: DictionaryItem[]; total: number; page: number; pageSize: number }>(
withQuery('/admin/dictionaries/phone-carrier-rules', query),
),
createPhoneCarrierRule: (body: {
carrier: string;
pattern: string;
priority?: number;
status?: string;
remark?: string;
}) =>
request<DictionaryItem>('/admin/dictionaries/phone-carrier-rules', { method: 'POST', body: JSON.stringify(body) }),
deletePhoneCarrierRule: (id: string) =>
request<DictionaryItem>(`/admin/dictionaries/phone-carrier-rules/${id}`, { method: 'DELETE' }),
listDrainageFields: () => request<DictionaryItem[]>('/admin/dictionaries/drainage-fields'),
createDrainageField: (body: {
code: string;
name: string;
fieldType: 'string' | 'image' | 'file';
required?: boolean;
status?: string;
description?: string;
}) => request<DictionaryItem>('/admin/dictionaries/drainage-fields', { method: 'POST', body: JSON.stringify(body) }),
updateDrainageField: (
id: string,
body: { code: string; name: string; fieldType: 'string' | 'image' | 'file'; description?: string },
) =>
request<DictionaryItem>(`/admin/dictionaries/drainage-fields/${id}`, { method: 'PUT', body: JSON.stringify(body) }),
deleteDrainageField: (id: string) =>
request<DictionaryItem>(`/admin/dictionaries/drainage-fields/${id}`, { method: 'DELETE' }),
listDrainageDetectionRules: (query: { keyword?: string; status?: string } = {}) =>
request<DrainageDetectionRule[]>(withQuery('/admin/dictionaries/drainage-detection-rules', query)),
createDrainageDetectionRule: (body: Omit<DrainageDetectionRule, 'id' | 'version' | 'createdAt' | 'updatedAt'>) =>
request<DrainageDetectionRule>('/admin/dictionaries/drainage-detection-rules', {
method: 'POST',
body: JSON.stringify(body),
}),
updateDrainageDetectionRule: (
id: string,
body: Omit<DrainageDetectionRule, 'id' | 'version' | 'createdAt' | 'updatedAt'>,
) =>
request<DrainageDetectionRule>(`/admin/dictionaries/drainage-detection-rules/${id}`, {
method: 'PUT',
body: JSON.stringify(body),
}),
changeDrainageDetectionRuleStatus: (id: string, status: 'active' | 'inactive') =>
request<DrainageDetectionRule>(`/admin/dictionaries/drainage-detection-rules/${id}/status`, {
method: 'POST',
body: JSON.stringify({ status }),
}),
testDrainageDetectionRule: (body: {
content: string;
rule?: Omit<DrainageDetectionRule, 'id' | 'version' | 'createdAt' | 'updatedAt'>;
}) =>
request<DrainageDetectionResult>('/admin/dictionaries/drainage-detection-rules/test', {
method: 'POST',
body: JSON.stringify(body),
}),
listCommonReportFields: () => request<CommonReportField[]>('/admin/dictionaries/common-report-fields'),
createCommonReportField: (body: {
drainageFieldId: string;
reportType: 'signature' | 'drainage';
required: boolean;
sortOrder?: number;
}) =>
request<CommonReportField>('/admin/dictionaries/common-report-fields', {
method: 'POST',
body: JSON.stringify(body),
}),
reorderCommonReportFields: (body: { reportType: 'signature' | 'drainage'; ids: string[] }) =>
request<CommonReportField[]>('/admin/dictionaries/common-report-fields/order', {
method: 'PUT',
body: JSON.stringify(body),
}),
deleteCommonReportField: (id: string) =>
request<CommonReportField>(`/admin/dictionaries/common-report-fields/${id}`, { method: 'DELETE' }),
updateCommonReportField: (
id: string,
body: { drainageFieldId: string; reportType: 'signature' | 'drainage'; required: boolean },
) =>
request<CommonReportField>(`/admin/dictionaries/common-report-fields/${id}`, {
method: 'PUT',
body: JSON.stringify(body),
}),
};