Files
gongxue-base/apps/taro/src/services/tenantAdmin.ts
2026-06-29 14:37:09 +08:00

528 lines
15 KiB
TypeScript

import { apiRequest } from './api';
export interface TenantDashboard {
scope?: Record<string, unknown>;
cards?: {
students?: Record<string, number>;
learning?: Record<string, number>;
content?: Record<string, number>;
activationCodes?: Record<string, number>;
feedback?: Record<string, number>;
};
paymentStats?: Record<string, number>;
trends?: Record<string, unknown>[];
activeHours?: Record<string, unknown>[];
questionDistribution?: Record<string, unknown>[];
subjectTop?: Record<string, unknown>[];
regionStats?: Record<string, unknown>[];
planSales?: Record<string, unknown>[];
recentActivities?: Record<string, unknown>[];
}
export interface TenantClassItem {
id: string;
name: string;
code?: string | null;
status?: string;
regionName?: string | null;
studentCount?: number;
teacherCount?: number;
}
export interface TenantStudentItem {
userId: string;
name?: string | null;
phone?: string | null;
email?: string | null;
status?: string;
regionName?: string | null;
selectedSchoolName?: string | null;
selectedMajorName?: string | null;
questionsAnsweredToday?: number;
masteredWordsCount?: number;
classes?: Record<string, unknown>[];
}
export interface ImportJobItem {
id: string;
importType?: string;
sourceFormat?: string;
status?: string;
sourceName?: string | null;
totalCount?: number;
validCount?: number;
successCount?: number;
errorCount?: number;
warningCount?: number;
insertedCount?: number;
updatedCount?: number;
skippedCount?: number;
executionMode?: string;
queuedAt?: string | null;
lockedAt?: string | null;
lockedBy?: string | null;
attemptCount?: number;
maxAttempts?: number;
nextAttemptAt?: string | null;
errorMessage?: string | null;
createdAt?: string;
updatedAt?: string;
finishedAt?: string | null;
summary?: Record<string, unknown>;
}
export interface ImportJobDetail {
item?: ImportJobItem;
issueSummary?: Record<string, number>;
itemStatusSummary?: Record<string, number>;
recentIssues?: ImportIssueItem[];
importPostCheck?: Record<string, unknown> | null;
worker?: {
executionMode?: string;
queuedAt?: string | null;
lockedAt?: string | null;
lockedBy?: string | null;
attemptCount?: number;
maxAttempts?: number;
nextAttemptAt?: string | null;
lastWorkerError?: Record<string, unknown>;
};
}
export interface ContentEntryAdminItem {
id: string;
name: string;
entryType?: string;
visibility?: string;
isActive?: boolean;
regionName?: string | null;
}
export interface PublicQuestionBankItem {
grantId?: string;
sourceQuestionBankId?: string;
sourceQuestionBankName?: string;
sourceRegionName?: string | null;
name?: string;
regionName?: string | null;
grantScope?: string;
questionCount?: number;
adoptedId?: string | null;
adoptionStatus?: string | null;
syncStatus?: string | null;
targetEntryId?: string | null;
targetCollectionId?: string | null;
copiedQuestionCount?: number;
lastSyncedAt?: string | null;
adoption?: Record<string, unknown> | null;
}
export interface PublicQuestionBankConflictItem {
sourceQuestionId?: string;
targetQuestionId?: string | null;
action?: string;
sourceHash?: string;
previousSourceHash?: string | null;
targetHash?: string | null;
}
export interface PublicQuestionBankConflictsResult {
adoptionId?: string;
syncStatus?: string;
status?: string;
lastSyncedAt?: string | null;
updatedAt?: string;
conflictCount?: number;
counts?: Record<string, unknown>;
conflicts?: PublicQuestionBankConflictItem[];
}
export interface ImportIssueItem {
id: string;
rowNo?: number | null;
severity?: string;
code?: string;
fieldPath?: string | null;
message?: string;
externalId?: string | null;
itemStatus?: string | null;
createdAt?: string;
}
export interface ImportFieldMapping {
importType?: string;
title?: string;
description?: string;
fields?: Array<{
field?: string;
label?: string;
required?: boolean;
aliases?: string[];
description?: string;
example?: unknown;
}>;
requiredFields?: string[];
}
export interface ImportTemplateItem {
importType?: string;
format?: string;
fileName?: string;
mimeType?: string;
contentBase64?: string;
contentPreview?: string;
fields?: Record<string, unknown>[];
}
export interface ImportPreviewResult {
job?: {
id: string;
status?: string;
totalCount?: number;
validCount?: number;
errorCount?: number;
warningCount?: number;
};
items?: Array<{
rowNo?: number;
status?: string;
externalId?: string | null;
normalized?: Record<string, unknown> | null;
issues?: ImportIssueItem[];
}>;
issues?: ImportIssueItem[];
}
export type ImportType = 'questions' | 'vocabulary' | 'handbook' | 'scoreline' | 'videos';
export type ImportSourceFormat = 'json' | 'csv' | 'excel';
export interface ImportRequestBody {
sourceFormat?: ImportSourceFormat;
sourceName?: string;
payload?: unknown;
items?: unknown[];
csvText?: string;
fileBase64?: string;
allowPartial?: boolean;
executionMode?: 'sync' | 'async';
previewJobId?: string;
jobId?: string;
regionId?: string;
entryId?: string;
contentNodeId?: string;
collectionId?: string;
fieldMappingOverrides?: Record<string, string[]>;
fieldMappingPreset?: ImportFieldMapping | null;
}
export interface CouponItem {
id: string;
code: string;
status?: string;
discountType?: string | null;
discountValue?: number | string | null;
usedCount?: number;
maxUses?: number | null;
}
export interface CodeBatchItem {
id: string;
name?: string | null;
batchNo?: string | null;
totalCount?: number;
usedCount?: number;
status?: string;
}
export interface TenantOverview {
id?: string;
name?: string;
slug?: string;
status?: string;
brandName?: string;
shortName?: string;
slogan?: string | null;
logoUrl?: string | null;
theme?: Record<string, unknown>;
featureFlags?: Record<string, unknown>;
adminFeatureFlags?: Record<string, unknown>;
publicConfig?: Record<string, unknown>;
}
export interface TenantPermissionCatalogItem {
key: string;
label?: string;
description?: string;
}
export interface TenantPermissionsPayload {
current?: Record<string, unknown>;
permissions?: TenantPermissionCatalogItem[];
menuGroups?: TenantPermissionCatalogItem[];
fieldGroups?: TenantPermissionCatalogItem[];
fieldCatalog?: TenantPermissionCatalogItem[];
roleDefaults?: Record<string, string[]>;
}
export interface TenantRoleTemplateItem {
id: string;
code: string;
name: string;
description?: string | null;
baseRole?: string;
status?: string;
permissions?: Record<string, boolean>;
menuPermissions?: Record<string, boolean>;
modulePermissions?: Record<string, boolean>;
fieldPermissions?: Record<string, boolean>;
dataScope?: Record<string, unknown>;
isSystem?: boolean;
sortOrder?: number;
createdAt?: string;
updatedAt?: string;
}
export interface TenantRoleTemplateInput {
id?: string;
code: string;
name: string;
description?: string | null;
baseRole: string;
status?: string;
permissions?: Record<string, boolean>;
menuPermissions?: Record<string, boolean>;
modulePermissions?: Record<string, boolean>;
fieldPermissions?: Record<string, boolean>;
dataScope?: Record<string, unknown>;
sortOrder?: number;
}
export interface TenantMemberItem {
id: string;
userId: string;
username?: string | null;
name?: string | null;
phone?: string | null;
email?: string | null;
avatarUrl?: string | null;
primaryRole?: string | null;
role: string;
status?: string;
permissions?: Record<string, boolean>;
roleTemplateId?: string | null;
roleTemplateCode?: string | null;
roleTemplateName?: string | null;
menuPermissions?: Record<string, boolean>;
modulePermissions?: Record<string, boolean>;
fieldPermissions?: Record<string, boolean>;
dataScope?: Record<string, unknown>;
legacyRole?: string | null;
lastSeenAt?: string | null;
createdAt?: string;
updatedAt?: string;
}
export interface TenantMemberInput {
membershipId?: string;
userId?: string;
username?: string | null;
name?: string | null;
phone?: string | null;
email?: string | null;
primaryRole?: string | null;
role: string;
status?: string;
permissions?: Record<string, boolean>;
roleTemplateId?: string | null;
}
export async function loadTenantDashboard(timeRange = '30d') {
return apiRequest<{ item?: TenantDashboard }>('/api/tenant-admin/dashboard', { query: { timeRange } });
}
export async function loadTenantOverview() {
return apiRequest<{ item?: TenantOverview }>('/api/tenant-admin/overview');
}
export async function loadTenantPermissions() {
return apiRequest<TenantPermissionsPayload>('/api/tenant-admin/permissions');
}
export async function loadTenantClasses(limit = 50) {
return apiRequest<{ items?: TenantClassItem[]; scoped?: boolean }>('/api/tenant-admin/classes', { query: { limit } });
}
export async function loadTenantStudents(query: { keyword?: string; classId?: string; limit?: number } = {}) {
return apiRequest<{ items?: TenantStudentItem[]; scoped?: boolean }>('/api/tenant-admin/students', {
query: { ...query, limit: query.limit || 50 },
});
}
export async function loadContentEntriesAdmin() {
return apiRequest<{ items?: ContentEntryAdminItem[] }>('/api/tenant-content/content-entries');
}
export async function loadImportJobs(limit = 20) {
return apiRequest<{ items?: ImportJobItem[] }>('/api/tenant-content/imports', { query: { limit } });
}
export async function loadImportJobDetail(jobId: string) {
return apiRequest<ImportJobDetail>('/api/tenant-content/imports/detail', { query: { jobId } });
}
export async function loadImportIssues(jobId: string) {
return apiRequest<{ items?: ImportIssueItem[] }>('/api/tenant-content/imports/issues', { query: { jobId } });
}
export async function loadPublicQuestionBanks() {
return apiRequest<{ items?: PublicQuestionBankItem[] }>('/api/tenant-content/public-question-banks');
}
export async function adoptPublicQuestionBank(input: { grantId: string; entryName?: string; collectionName?: string; copyLimit?: number }) {
return apiRequest<{ item?: Record<string, unknown> }>('/api/tenant-content/public-question-banks/adopt', {
method: 'POST',
body: input,
});
}
export async function syncPublicQuestionBank(input: { adoptionId: string; copyLimit?: number }) {
return apiRequest<{ item?: Record<string, unknown>; sync?: Record<string, unknown> }>('/api/tenant-content/public-question-banks/sync', {
method: 'POST',
body: input,
});
}
export async function loadPublicQuestionBankConflicts(adoptionId: string) {
return apiRequest<{ item?: PublicQuestionBankConflictsResult }>('/api/tenant-content/public-question-banks/conflicts', {
query: { adoptionId },
});
}
export async function resolvePublicQuestionBankConflict(input: { adoptionId: string; sourceQuestionId: string; resolution: 'accept_platform' | 'keep_local' }) {
return apiRequest<{ item?: Record<string, unknown> }>('/api/tenant-content/public-question-banks/conflicts/resolve', {
method: 'POST',
body: input,
});
}
export async function resolvePublicQuestionBankConflicts(input: {
adoptionId: string;
sourceQuestionIds: string[];
resolution: 'accept_platform' | 'keep_local';
limit?: number;
}) {
return apiRequest<{ item?: Record<string, unknown> }>('/api/tenant-content/public-question-banks/conflicts/resolve-batch', {
method: 'POST',
body: input,
});
}
export async function runImportPostCheck(jobId: string) {
return apiRequest<{ item?: Record<string, unknown> }>('/api/tenant-content/imports/post-check', {
method: 'POST',
body: { jobId },
});
}
export async function loadImportPostCheck(jobId: string) {
return apiRequest<{ item?: Record<string, unknown> }>('/api/tenant-content/imports/post-check', {
query: { jobId },
});
}
export async function loadImportFieldMapping(importType: string) {
return apiRequest<{ item?: ImportFieldMapping }>('/api/tenant-content/imports/field-mapping', {
query: { importType },
});
}
export async function loadImportTemplate(importType: string, format: 'json' | 'csv' = 'json') {
return apiRequest<{ item?: ImportTemplateItem }>('/api/tenant-content/imports/templates', {
query: { importType, format },
});
}
export async function previewContentImport(importType: ImportType, body: ImportRequestBody) {
return apiRequest<ImportPreviewResult>(`/api/tenant-content/imports/preview/${importType}`, {
method: 'POST',
body,
});
}
export async function executeContentImport(importType: ImportType, body: ImportRequestBody) {
return apiRequest<{ item?: Record<string, unknown>; preview?: ImportPreviewResult }>(`/api/tenant-content/imports/${importType}`, {
method: 'POST',
body,
});
}
export async function loadCoupons() {
return apiRequest<{ items?: CouponItem[] }>('/api/tenant-admin/coupons');
}
export async function loadCodeBatches() {
return apiRequest<{ items?: CodeBatchItem[] }>('/api/tenant-admin/code-batches');
}
export async function loadActivationCodes(limit = 20) {
return apiRequest<{ items?: Record<string, unknown>[] }>('/api/tenant-admin/activation-codes', { query: { limit } });
}
export async function loadTenantDomains() {
return apiRequest<{ items?: Record<string, unknown>[] }>('/api/tenant-admin/domains');
}
export async function loadPaymentAccounts() {
return apiRequest<{ items?: Record<string, unknown>[] }>('/api/tenant-admin/payment-accounts');
}
export async function loadAuthProviders() {
return apiRequest<{ items?: Record<string, unknown>[] }>('/api/tenant-admin/auth-providers');
}
export async function loadRoleTemplates() {
return apiRequest<{ items?: TenantRoleTemplateItem[] }>('/api/tenant-admin/role-templates');
}
export async function upsertRoleTemplate(input: TenantRoleTemplateInput) {
return apiRequest<{ item?: TenantRoleTemplateItem }>('/api/tenant-admin/role-templates', {
method: 'PUT',
body: input,
});
}
export async function disableRoleTemplate(roleTemplateId: string) {
return apiRequest<{ item?: TenantRoleTemplateItem }>('/api/tenant-admin/role-templates/disable', {
method: 'POST',
body: { roleTemplateId },
});
}
export async function loadTenantMembers(query: { keyword?: string; role?: string; status?: string; limit?: number } = {}) {
return apiRequest<{ items?: TenantMemberItem[] }>('/api/tenant-admin/members', {
query: { ...query, limit: query.limit || 50 },
});
}
export async function upsertTenantMember(input: TenantMemberInput) {
return apiRequest<{ item?: TenantMemberItem }>('/api/tenant-admin/members', {
method: 'PUT',
body: input,
});
}
export async function disableTenantMember(membershipId: string) {
return apiRequest<{ item?: TenantMemberItem }>('/api/tenant-admin/members/disable', {
method: 'POST',
body: { membershipId },
});
}
export async function loadCrmQueue(limit = 20) {
return apiRequest<{ items?: Record<string, unknown>[] }>('/api/crm/queue', { query: { limit } });
}
export async function loadCommissionSummary() {
return apiRequest<{ item?: Record<string, unknown> }>('/api/commission/summary');
}