feat: add student supervision automation

This commit is contained in:
Codex
2026-06-30 17:07:51 +08:00
parent 7473c7a6d7
commit 0204c934d8
14 changed files with 803 additions and 16 deletions

View File

@@ -174,6 +174,40 @@ export interface TenantStudentFollowupReport {
};
}
export interface TenantStudentSupervisionRules {
windowDays?: number;
inactivityDays?: number;
minAnswers?: number;
lowAccuracyThreshold?: number;
wrongQuestionThreshold?: number;
vocabularyDueThreshold?: number;
staleSessionDays?: number;
}
export interface TenantStudentSupervisionCandidate {
studentUserId: string;
studentName?: string | null;
studentPhone?: string | null;
assignedToUserId?: string | null;
classId?: string | null;
title?: string;
description?: string;
followupType?: string;
priority?: string;
riskScore?: number;
reasons?: Record<string, unknown>[];
evidence?: Record<string, unknown>;
}
export interface TenantStudentSupervisionPreview {
item?: {
rules?: TenantStudentSupervisionRules;
filters?: Record<string, unknown>;
totalCandidates?: number;
candidates?: TenantStudentSupervisionCandidate[];
};
}
export interface ImportJobItem {
id: string;
importType?: string;
@@ -1113,6 +1147,32 @@ export async function loadTenantStudentFollowupReport(query: {
});
}
export async function previewTenantStudentSupervision(query: TenantStudentSupervisionRules & {
classId?: string;
assignedToUserId?: string;
limit?: number;
} = {}) {
return apiRequest<TenantStudentSupervisionPreview>('/api/tenant-admin/students/supervision/preview', {
query: { ...query, limit: query.limit || 20 },
});
}
export async function generateTenantStudentSupervision(input: {
rules?: TenantStudentSupervisionRules;
classId?: string | null;
assignedToUserId?: string | null;
studentUserIds?: string[];
dueAt?: string | null;
batchKey?: string;
limit?: number;
metadata?: Record<string, unknown>;
}) {
return apiRequest<BulkOperationResult>('/api/tenant-admin/students/supervision/generate', {
method: 'POST',
body: input,
});
}
export async function upsertTenantStudentFollowup(input: {
id?: string;
studentUserId: string;