147 lines
5.3 KiB
TypeScript
147 lines
5.3 KiB
TypeScript
/**
|
|
* API аналитики ментора (отдельная страница, не профиль).
|
|
* Период по умолчанию на странице аналитики — последние 30 дней.
|
|
*/
|
|
|
|
import apiClient from '@/lib/api-client';
|
|
|
|
export type AnalyticsPeriod = 'day' | 'week' | 'month' | 'year' | 'custom';
|
|
|
|
export interface AnalyticsDateRange {
|
|
period: AnalyticsPeriod;
|
|
start_date: string; // YYYY-MM-DD
|
|
end_date: string;
|
|
}
|
|
|
|
export interface AnalyticsOverview {
|
|
period: { start: string; end: string };
|
|
lessons: { total: number; completed: number; cancelled: number };
|
|
revenue: { total: number; average_per_lesson: number };
|
|
students: { active: number };
|
|
homeworks: { total: number; pending: number };
|
|
grades: { average: number };
|
|
}
|
|
|
|
export interface StudentStat {
|
|
id: number;
|
|
name: string;
|
|
email: string;
|
|
lessons_total: number;
|
|
lessons_completed: number;
|
|
average_grade: number;
|
|
revenue: number;
|
|
}
|
|
|
|
export interface AnalyticsStudentsResponse {
|
|
students: StudentStat[];
|
|
total_count: number;
|
|
}
|
|
|
|
export interface AnalyticsRevenueResponse {
|
|
total_revenue: number;
|
|
by_day: { date: string; revenue: number; lessons_count: number }[];
|
|
by_subject: { subject: string; revenue: number; lessons_count: number }[];
|
|
}
|
|
|
|
export interface AnalyticsLessonsStatsResponse {
|
|
by_status: { status: string; count: number }[];
|
|
by_subject: { subject: string; count: number }[];
|
|
by_weekday: { day: string; count: number }[];
|
|
}
|
|
|
|
/** Средняя оценка по дням (успех учеников / продуктивность репетитора) */
|
|
export interface AnalyticsGradesByDayResponse {
|
|
period: { start: string; end: string };
|
|
by_day: {
|
|
date: string;
|
|
average_grade: number | null;
|
|
lessons_count: number;
|
|
graded_count: number;
|
|
}[];
|
|
summary: {
|
|
total_lessons: number;
|
|
graded_lessons: number;
|
|
average_grade: number;
|
|
};
|
|
}
|
|
|
|
/** Последние 30 дней (по умолчанию на странице аналитики). */
|
|
export function getLast30DaysRange(): { start_date: string; end_date: string } {
|
|
const now = new Date();
|
|
const end = new Date(now);
|
|
const start = new Date(now);
|
|
start.setDate(start.getDate() - 29); // 30 дней включительно: сегодня минус 29
|
|
const fmt = (d: Date) => d.toISOString().slice(0, 10);
|
|
return { start_date: fmt(start), end_date: fmt(end) };
|
|
}
|
|
|
|
export function getCurrentWeekRange(): { start_date: string; end_date: string } {
|
|
const now = new Date();
|
|
const day = now.getDay();
|
|
const diff = day === 0 ? -6 : 1 - day; // понедельник
|
|
const monday = new Date(now);
|
|
monday.setDate(now.getDate() + diff);
|
|
const sunday = new Date(monday);
|
|
sunday.setDate(monday.getDate() + 6);
|
|
const fmt = (d: Date) => d.toISOString().slice(0, 10);
|
|
return { start_date: fmt(monday), end_date: fmt(sunday) };
|
|
}
|
|
|
|
function getWeekRange(): { start: string; end: string } {
|
|
const r = getCurrentWeekRange();
|
|
return { start: r.start_date, end: r.end_date };
|
|
}
|
|
|
|
export function getDefaultDateRange(): AnalyticsDateRange {
|
|
const { start, end } = getWeekRange();
|
|
return { period: 'week', start_date: start, end_date: end };
|
|
}
|
|
|
|
/** Преобразовать диапазон дат в AnalyticsDateRange для API (всегда custom) */
|
|
export function toAnalyticsRange(r: { start_date: string; end_date: string }): AnalyticsDateRange {
|
|
return { period: 'custom', start_date: r.start_date, end_date: r.end_date };
|
|
}
|
|
|
|
function buildParams(range: AnalyticsDateRange): string {
|
|
const p = new URLSearchParams();
|
|
p.set('period', range.period === 'custom' ? 'custom' : range.period);
|
|
p.set('start_date', range.start_date);
|
|
p.set('end_date', range.end_date);
|
|
return p.toString();
|
|
}
|
|
|
|
export async function getAnalyticsOverview(range: AnalyticsDateRange): Promise<AnalyticsOverview> {
|
|
const q = buildParams(range);
|
|
const url = q ? `/analytics/overview?${q}` : '/analytics/overview';
|
|
const res = await apiClient.get<AnalyticsOverview>(url);
|
|
return res.data;
|
|
}
|
|
|
|
export async function getAnalyticsStudents(range: AnalyticsDateRange): Promise<AnalyticsStudentsResponse> {
|
|
const q = buildParams(range);
|
|
const url = q ? `/analytics/students?${q}` : '/analytics/students';
|
|
const res = await apiClient.get<AnalyticsStudentsResponse>(url);
|
|
return res.data;
|
|
}
|
|
|
|
export async function getAnalyticsRevenue(range: AnalyticsDateRange): Promise<AnalyticsRevenueResponse> {
|
|
const q = buildParams(range);
|
|
const url = q ? `/analytics/revenue?${q}` : '/analytics/revenue';
|
|
const res = await apiClient.get<AnalyticsRevenueResponse>(url);
|
|
return res.data;
|
|
}
|
|
|
|
export async function getAnalyticsLessonsStats(range: AnalyticsDateRange): Promise<AnalyticsLessonsStatsResponse> {
|
|
const q = buildParams(range);
|
|
const url = q ? `/analytics/lessons_stats?${q}` : '/analytics/lessons_stats';
|
|
const res = await apiClient.get<AnalyticsLessonsStatsResponse>(url);
|
|
return res.data;
|
|
}
|
|
|
|
export async function getAnalyticsGradesByDay(range: AnalyticsDateRange): Promise<AnalyticsGradesByDayResponse> {
|
|
const q = buildParams(range);
|
|
const url = q ? `/analytics/grades_by_day?${q}` : '/analytics/grades_by_day';
|
|
const res = await apiClient.get<AnalyticsGradesByDayResponse>(url);
|
|
return res.data;
|
|
}
|