import { apiRequest } from './api'; export interface TenantDashboard { scope?: Record; cards?: { students?: Record; learning?: Record; content?: Record; activationCodes?: Record; feedback?: Record; }; paymentStats?: Record; trends?: Record[]; activeHours?: Record[]; questionDistribution?: Record[]; subjectTop?: Record[]; regionStats?: Record[]; planSales?: Record[]; recentActivities?: Record[]; } export interface TenantClassItem { id: string; name: string; code?: string | null; status?: string; regionName?: string | null; studentCount?: number; teacherCount?: number; } export interface TenantStudentItem { membershipId?: string; userId: string; username?: string | null; name?: string | null; phone?: string | null; email?: string | null; status?: string; profileId?: string; regionId?: string | null; regionName?: string | null; selectedSchoolId?: string | null; selectedSchoolName?: string | null; selectedMajorId?: string | null; selectedMajorName?: string | null; questionsAnsweredToday?: number; masteredWordsCount?: number; lastSeenAt?: string | null; classes?: Record[]; } export interface TenantStudentInput { userId?: string; username?: string | null; name?: string | null; phone?: string | null; email?: string | null; regionId?: string | null; selectedSchoolId?: string | null; selectedMajorId?: string | null; status?: string; stats?: Record; progress?: Record; moduleSelections?: Record; } export interface TenantTeacherItem { membershipId?: string; userId: string; username?: string | null; name?: string | null; phone?: string | null; email?: string | null; status?: string; classCount?: number; } export interface BulkOperationResult { total?: number; successCount?: number; errorCount?: number; items?: Record[]; errors?: Array<{ index?: number; code?: string; message?: string; }>; } export interface TenantStudentNoteItem { id: string; studentUserId?: string; noteType?: string; content?: string; visibility?: string; isPinned?: boolean; metadata?: Record; createdByName?: string | null; createdByUsername?: string | null; createdAt?: string; updatedAt?: string; } export interface TenantStudentFollowupItem { id: string; studentUserId?: string; studentName?: string | null; studentPhone?: string | null; assignedToUserId?: string | null; assignedToName?: string | null; classId?: string | null; className?: string | null; title?: string; description?: string | null; followupType?: string; priority?: string; status?: string; dueAt?: string | null; completedAt?: string | null; completedBy?: string | null; metadata?: Record; createdAt?: string; updatedAt?: string; } 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; } export interface ImportJobDetail { item?: ImportJobItem; issueSummary?: Record; itemStatusSummary?: Record; recentIssues?: ImportIssueItem[]; importPostCheck?: Record | null; worker?: { executionMode?: string; queuedAt?: string | null; lockedAt?: string | null; lockedBy?: string | null; attemptCount?: number; maxAttempts?: number; nextAttemptAt?: string | null; lastWorkerError?: Record; }; } 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 | 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; conflicts?: PublicQuestionBankConflictItem[]; } export interface TenantContentNotificationItem { id: string; notificationType?: string; status?: 'unread' | 'read' | 'dismissed' | 'resolved'; severity?: 'info' | 'success' | 'warning' | 'error'; adoptionId?: string | null; sourceQuestionBankId?: string | null; title?: string; message?: string; actionLabel?: string | null; actionPath?: string | null; metadata?: Record; createdAt?: string; updatedAt?: string; readAt?: string | null; resolvedAt?: string | null; } 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[]; } 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 | 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; 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 CrmConfigItem { id?: string; enabled?: boolean; url?: string | null; secretRef?: string | null; formName?: string | null; examType?: string | null; timeoutSec?: number; delaySec?: number; updatedAt?: string; } export interface CrmQueueItem { id: string; recordId?: string | null; status?: string; scheduledAt?: string | null; attempts?: number; nextAttemptAt?: string | null; lastError?: string | null; lastHttpCode?: number | null; leadId?: string | null; sentAt?: string | null; source?: string | null; targetUrl?: string | null; payload?: Record; createdAt?: string; } export interface CommissionSettingsItem { defaultRate?: number | string; minSettlementCents?: number; settlementCycle?: string; config?: Record; updatedAt?: string; } export interface CommissionSummaryItem { tenantId?: string; startDate?: string; endDate?: string; referrerUserId?: string | null; defaultRate?: number | string; minSettlementCents?: number; sourceCount?: number; paidUserCount?: number; grossAmountCents?: number; commissionAmountCents?: number; byReferrer?: Record[]; } export interface CommissionOrderItem { sourceType?: string; sourceId?: string; sourceNo?: string | null; referrerUserId?: string; referrerName?: string | null; referrerPhone?: string | null; studentUserId?: string | null; studentName?: string | null; grossAmountCents?: number; commissionRate?: number | string; commissionAmountCents?: number; rateSource?: string; settlementId?: string | null; sourcePaidAt?: string | null; } export interface CommissionSettlementItem { id: string; settlementNo?: string; referrerUserId?: string; referrerName?: string | null; referrerPhone?: string | null; status?: string; periodStart?: string; periodEnd?: string; sourceCount?: number; paidUserCount?: number; grossAmountCents?: number; commissionAmountCents?: number; defaultRate?: number | string; effectiveRate?: number | string; reviewedBy?: string | null; reviewedAt?: string | null; paidBy?: string | null; paidAt?: string | null; paymentMethod?: string | null; paymentAccount?: string | null; remark?: string | null; metadata?: Record; createdAt?: string; updatedAt?: string; } export interface TenantOverview { id?: string; name?: string; slug?: string; status?: string; brandName?: string; shortName?: string; slogan?: string | null; logoUrl?: string | null; theme?: Record; featureFlags?: Record; adminFeatureFlags?: Record; publicConfig?: Record; } export interface TenantPermissionCatalogItem { key: string; label?: string; description?: string; } export interface TenantPermissionsPayload { current?: Record; permissions?: TenantPermissionCatalogItem[]; menuGroups?: TenantPermissionCatalogItem[]; fieldGroups?: TenantPermissionCatalogItem[]; fieldCatalog?: TenantPermissionCatalogItem[]; roleDefaults?: Record; } export interface TenantRoleTemplateItem { id: string; code: string; name: string; description?: string | null; baseRole?: string; status?: string; permissions?: Record; menuPermissions?: Record; modulePermissions?: Record; fieldPermissions?: Record; dataScope?: Record; 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; menuPermissions?: Record; modulePermissions?: Record; fieldPermissions?: Record; dataScope?: Record; 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; roleTemplateId?: string | null; roleTemplateCode?: string | null; roleTemplateName?: string | null; menuPermissions?: Record; modulePermissions?: Record; fieldPermissions?: Record; dataScope?: Record; 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; 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('/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; status?: string; limit?: number } = {}) { return apiRequest<{ items?: TenantStudentItem[]; scoped?: boolean }>('/api/tenant-admin/students', { query: { ...query, limit: query.limit || 50 }, }); } export async function upsertTenantStudent(input: TenantStudentInput) { return apiRequest<{ item?: Record }>('/api/tenant-admin/students', { method: 'PUT', body: input, }); } export async function bulkUpsertTenantStudents(students: TenantStudentInput[]) { return apiRequest('/api/tenant-admin/students/bulk-upsert', { method: 'POST', body: { students }, }); } export async function updateTenantStudentStatus(input: { userId: string; status: string; reason?: string | null }) { return apiRequest<{ item?: Record }>('/api/tenant-admin/students/status', { method: 'POST', body: input, }); } export async function bulkAssignTenantClassMembers(input: { classId: string; assignments: Array<{ userId?: string; username?: string | null; name?: string | null; phone?: string | null; email?: string | null; memberType?: string; status?: string; metadata?: Record; }>; }) { return apiRequest('/api/tenant-admin/classes/members/bulk-assign', { method: 'POST', body: input, }); } export async function loadTenantTeachers(query: { keyword?: string; limit?: number } = {}) { return apiRequest<{ items?: TenantTeacherItem[] }>('/api/tenant-admin/teachers', { query: { ...query, limit: query.limit || 50 }, }); } export async function loadTenantStudentNotes(studentUserId: string, limit = 20) { return apiRequest<{ items?: TenantStudentNoteItem[] }>('/api/tenant-admin/students/notes', { query: { studentUserId, limit }, }); } export async function upsertTenantStudentNote(input: { id?: string; studentUserId: string; noteType?: string; content: string; visibility?: string; isPinned?: boolean; metadata?: Record; }) { return apiRequest<{ item?: TenantStudentNoteItem }>('/api/tenant-admin/students/notes', { method: 'PUT', body: input, }); } export async function loadTenantStudentFollowups(query: { studentUserId?: string; status?: string; assignedToUserId?: string; limit?: number; } = {}) { return apiRequest<{ items?: TenantStudentFollowupItem[] }>('/api/tenant-admin/students/followups', { query: { ...query, limit: query.limit || 50 }, }); } export async function upsertTenantStudentFollowup(input: { id?: string; studentUserId: string; assignedToUserId?: string | null; classId?: string | null; title: string; description?: string | null; followupType?: string; priority?: string; status?: string; dueAt?: string | null; metadata?: Record; }) { return apiRequest<{ item?: TenantStudentFollowupItem }>('/api/tenant-admin/students/followups', { method: 'PUT', body: input, }); } 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('/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 loadTenantContentNotifications(input: { status?: 'unread' | 'read' | 'dismissed' | 'resolved'; notificationType?: string; adoptionId?: string; limit?: number; } = {}) { return apiRequest<{ items?: TenantContentNotificationItem[]; summary?: Record }>('/api/tenant-content/notifications', { query: input, }); } export async function updateTenantContentNotificationStatus(input: { notificationIds: string[]; status: 'read' | 'dismissed' | 'resolved'; }) { return apiRequest<{ item?: Record }>('/api/tenant-content/notifications/status', { method: 'POST', body: input, }); } export async function adoptPublicQuestionBank(input: { grantId: string; entryName?: string; collectionName?: string; copyLimit?: number }) { return apiRequest<{ item?: Record }>('/api/tenant-content/public-question-banks/adopt', { method: 'POST', body: input, }); } export async function syncPublicQuestionBank(input: { adoptionId: string; copyLimit?: number }) { return apiRequest<{ item?: Record; sync?: Record }>('/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 }>('/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 }>('/api/tenant-content/public-question-banks/conflicts/resolve-batch', { method: 'POST', body: input, }); } export async function runImportPostCheck(jobId: string) { return apiRequest<{ item?: Record }>('/api/tenant-content/imports/post-check', { method: 'POST', body: { jobId }, }); } export async function loadImportPostCheck(jobId: string) { return apiRequest<{ item?: Record }>('/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(`/api/tenant-content/imports/preview/${importType}`, { method: 'POST', body, }); } export async function executeContentImport(importType: ImportType, body: ImportRequestBody) { return apiRequest<{ item?: Record; 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[] }>('/api/tenant-admin/activation-codes', { query: { limit } }); } export async function loadTenantDomains() { return apiRequest<{ items?: Record[] }>('/api/tenant-admin/domains'); } export async function loadPaymentAccounts() { return apiRequest<{ items?: Record[] }>('/api/tenant-admin/payment-accounts'); } export async function loadAuthProviders() { return apiRequest<{ items?: Record[] }>('/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 loadCrmConfig() { return apiRequest<{ item?: CrmConfigItem | null }>('/api/crm/config'); } export async function upsertCrmConfig(input: { enabled?: boolean; url?: string | null; secretRef?: string | null; formName?: string | null; examType?: string | null; timeoutSec?: number; delaySec?: number; }) { return apiRequest<{ item?: CrmConfigItem }>('/api/crm/config', { method: 'PUT', body: input, }); } export async function loadCrmQueue(limit = 20, status?: string) { return apiRequest<{ items?: CrmQueueItem[] }>('/api/crm/queue', { query: { limit, status } }); } export async function loadCommissionSettings() { return apiRequest<{ item?: CommissionSettingsItem }>('/api/commission/settings'); } export async function updateCommissionSettings(input: { defaultRate: number; minSettlementCents?: number; settlementCycle?: string; config?: Record; }) { return apiRequest<{ item?: CommissionSettingsItem }>('/api/commission/settings', { method: 'PUT', body: input, }); } export async function updateMemberCommissionRate(input: { userId: string; commissionRate?: number | null; commissionConfig?: Record; }) { return apiRequest<{ item?: Record }>('/api/commission/member-rate', { method: 'PUT', body: input, }); } export async function loadCommissionSummary(query: { startDate?: string; endDate?: string; referrerUserId?: string } = {}) { return apiRequest<{ item?: CommissionSummaryItem }>('/api/commission/summary', { query }); } export async function loadCommissionOrders(query: { startDate?: string; endDate?: string; referrerUserId?: string; limit?: number } = {}) { return apiRequest<{ items?: CommissionOrderItem[]; scope?: Record }>('/api/commission/orders', { query: { ...query, limit: query.limit || 50 }, }); } export async function loadCommissionSettlements(query: { status?: string; referrerUserId?: string; limit?: number } = {}) { return apiRequest<{ items?: CommissionSettlementItem[] }>('/api/commission/settlements', { query: { ...query, limit: query.limit || 50 }, }); } export async function generateCommissionSettlement(input: { referrerUserId: string; startDate: string; endDate: string; status?: string; remark?: string | null; }) { return apiRequest<{ item?: CommissionSettlementItem & { items?: CommissionOrderItem[] } }>('/api/commission/settlements/generate', { method: 'POST', body: input, }); } export async function updateCommissionSettlementStatus(input: { settlementId: string; status: string; paymentMethod?: string | null; paymentAccount?: string | null; remark?: string | null; metadata?: Record; }) { return apiRequest<{ item?: CommissionSettlementItem }>('/api/commission/settlements/status', { method: 'POST', body: input, }); }