forked from wangziqi/gongxue-base
528 lines
15 KiB
TypeScript
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');
|
|
}
|