forked from wangziqi/gongxue-base
feat: add student learning report dashboard
This commit is contained in:
@@ -119,19 +119,24 @@ export interface PracticeReport {
|
||||
export interface PracticeHistoryItem {
|
||||
id: string;
|
||||
mode: string;
|
||||
blueprintName?: string | null;
|
||||
collectionName?: string | null;
|
||||
entryName?: string | null;
|
||||
contentNodeName?: string | null;
|
||||
questionCount?: number;
|
||||
durationMinutes?: number | null;
|
||||
accessMode?: string | null;
|
||||
answeredCount?: number;
|
||||
correctCount?: number;
|
||||
wrongCount?: number;
|
||||
status?: string;
|
||||
reportId?: string | null;
|
||||
score?: number | null;
|
||||
reportTotalScore?: number | null;
|
||||
accuracy?: number | null;
|
||||
startedAt?: string;
|
||||
finishedAt?: string | null;
|
||||
submittedAt?: string | null;
|
||||
}
|
||||
|
||||
export interface WrongQuestionReviewItem {
|
||||
@@ -165,6 +170,86 @@ export interface VocabularyWord {
|
||||
note?: string | null;
|
||||
}
|
||||
|
||||
export interface LearningStats {
|
||||
windowDays: number;
|
||||
answers: {
|
||||
totalAnswered: number;
|
||||
correctCount: number;
|
||||
wrongCount: number;
|
||||
todayAnswered: number;
|
||||
accuracy: number;
|
||||
latestAnsweredAt?: string | null;
|
||||
};
|
||||
sessions: {
|
||||
totalSessions: number;
|
||||
activeSessions: number;
|
||||
finishedSessions: number;
|
||||
latestStartedAt?: string | null;
|
||||
};
|
||||
reports: {
|
||||
reportCount: number;
|
||||
avgAccuracy: number;
|
||||
bestScore: number;
|
||||
latestSubmittedAt?: string | null;
|
||||
};
|
||||
wrongBook: {
|
||||
unresolvedWrong: number;
|
||||
resolvedWrong: number;
|
||||
totalWrongBook: number;
|
||||
};
|
||||
favorites: {
|
||||
favoriteQuestions: number;
|
||||
};
|
||||
questionTypes: LearningQuestionTypeStats[];
|
||||
}
|
||||
|
||||
export interface LearningQuestionTypeStats {
|
||||
questionType: string;
|
||||
typeLabel?: string | null;
|
||||
answeredCount: number;
|
||||
correctCount: number;
|
||||
wrongCount: number;
|
||||
accuracy: number;
|
||||
}
|
||||
|
||||
export interface LearningTrendItem {
|
||||
date: string;
|
||||
answeredCount: number;
|
||||
correctCount: number;
|
||||
wrongCount: number;
|
||||
accuracy: number;
|
||||
sessionCount: number;
|
||||
reportCount: number;
|
||||
score: number;
|
||||
totalScore: number;
|
||||
}
|
||||
|
||||
export interface LeaderboardItem {
|
||||
rank: number;
|
||||
userId: string;
|
||||
displayName: string;
|
||||
avatarUrl?: string | null;
|
||||
primaryRole?: string;
|
||||
regionId?: string | null;
|
||||
regionName?: string | null;
|
||||
classIds?: string[];
|
||||
classNames?: string[];
|
||||
value: number;
|
||||
secondaryValue?: number | null;
|
||||
latestAt?: string | null;
|
||||
isCurrentUser?: boolean;
|
||||
}
|
||||
|
||||
export interface LeaderboardPayload {
|
||||
metric: 'questions' | 'score' | 'vocabulary' | 'mock_exam';
|
||||
label: string;
|
||||
unit: string;
|
||||
period: 'all' | '7d' | '30d';
|
||||
items?: LeaderboardItem[];
|
||||
currentUser?: LeaderboardItem | null;
|
||||
generatedAt?: string;
|
||||
}
|
||||
|
||||
export async function createPracticeSession(body: {
|
||||
blueprintId?: string;
|
||||
collectionId?: string;
|
||||
@@ -252,16 +337,20 @@ export async function loadFavoriteQuestions(limit = 30) {
|
||||
return apiRequest<{ items?: QuestionItem[] }>('/api/learning/favorites/questions', { query: { limit } });
|
||||
}
|
||||
|
||||
export async function loadLearningStats() {
|
||||
return apiRequest<{ item?: Record<string, unknown> }>('/api/learning/stats');
|
||||
export async function loadLearningStats(days = 30) {
|
||||
return apiRequest<{ item?: LearningStats }>('/api/learning/stats', { query: { days } });
|
||||
}
|
||||
|
||||
export async function loadLeaderboard(metric: 'questions' | 'score' | 'vocabulary' | 'mock_exam' = 'questions') {
|
||||
return apiRequest<{ items?: Record<string, unknown>[]; currentUserRank?: unknown }>('/api/learning/leaderboard', {
|
||||
return apiRequest<LeaderboardPayload>('/api/learning/leaderboard', {
|
||||
query: { metric, period: '7d', scope: 'tenant' },
|
||||
});
|
||||
}
|
||||
|
||||
export async function loadLearningTrend(days = 14) {
|
||||
return apiRequest<{ items?: LearningTrendItem[] }>('/api/learning/trend', { query: { days } });
|
||||
}
|
||||
|
||||
export async function loadVocabularyReviewPlan(unitId?: string) {
|
||||
return apiRequest<{ item?: { words?: VocabularyWord[]; dueCount?: number; newCount?: number; totalPlanned?: number } }>(
|
||||
'/api/learning/vocabulary/review-plan',
|
||||
|
||||
Reference in New Issue
Block a user