kindergarten_java/reading-platform-frontend/src/api/teacher.ts
zhonghua 5cb903d7ed feat: 家长端任务、教师端统计、数据库迁移等
- 家长端阅读任务:从 task_target 获取任务(学生+班级),支持家长关联孩子查看
- 家长端提交任务:修复照片上传,使用 uploadFile(file, poster) 符合 API 规范
- 教师端任务列表:TaskResponse 新增 targetCount、completionCount,填充目标人数与完成人数
- 数据库迁移:V45 添加 task_completion.photos,V46 添加 submitted_at、reviewed_at
- 其他:班级学生、家长孩子、学校班级统计等修复

Made-with: Cursor
2026-03-20 18:43:47 +08:00

894 lines
24 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { http } from './index';
// ============= 类型定义(保持向后兼容) =============
// ==================== 教师课程 API ====================
export interface TeacherCourseQueryParams {
pageNum?: number;
pageSize?: number;
grade?: string;
domain?: string;
lessonType?: string;
keyword?: string;
}
/** 课程环节标签(列表展示) */
export interface LessonTag {
name: string;
lessonType: string;
}
export interface TeacherCourse {
id: number;
name: string;
pictureBookName?: string;
coverImagePath?: string;
gradeTags: string[];
domainTags: string[];
lessonTags?: LessonTag[];
duration: number;
avgRating: number;
usageCount: number;
publishedAt: string;
}
// 教师班级信息(更新:新增角色字段)
export interface TeacherClass {
id: number;
name: string;
grade: string;
studentCount: number;
lessonCount: number;
myRole: 'MAIN' | 'ASSIST' | 'CARE'; // 我在该班级的角色
isPrimary: boolean; // 是否班主任
}
// 班级教师信息
export interface TeacherClassTeacher {
teacherId: number;
teacherName: string;
teacherPhone?: string;
role: 'MAIN' | 'ASSIST' | 'CARE';
isPrimary: boolean;
}
// 获取教师可用的课程列表
export function getTeacherCourses(params: TeacherCourseQueryParams): Promise<{
items: TeacherCourse[];
total: number;
page: number;
pageSize: number;
}> {
// 使用 http 直接调用 API后端返回 list 字段,需要转换为 items
return http.get<{ list?: TeacherCourse[]; records?: TeacherCourse[]; total?: number | string; pageNum?: number; pageSize?: number }>('/v1/teacher/courses', {
params: {
pageNum: params.pageNum,
pageSize: params.pageSize,
keyword: params.keyword,
grade: params.grade,
domain: params.domain,
lessonType: params.lessonType,
},
}).then(res => {
const list = res.list ?? res.records ?? [];
return {
items: Array.isArray(list) ? list : [],
total: typeof res.total === 'string' ? parseInt(res.total, 10) || 0 : (res.total || 0),
page: res.pageNum || 1,
pageSize: res.pageSize || 10,
};
});
}
// 获取课程详情id 使用 string 避免 Long 精度丢失)
export function getTeacherCourse(id: number | string): Promise<any> {
return http.get(`/v1/teacher/courses/${id}`) as any;
}
// 获取教师的班级列表
export function getTeacherClasses(): Promise<TeacherClass[]> {
return http.get<TeacherClass[]>('/v1/teacher/classes');
}
// 获取教师所有学生列表(跨班级)
export function getTeacherStudents(params?: { pageNum?: number; pageSize?: number; keyword?: string }): Promise<{
items: Array<{
id: number;
name: string;
gender?: string;
birthDate?: string;
classId: number;
class?: {
id: number;
name: string;
grade: string;
};
parentName?: string;
parentPhone?: string;
createdAt: string;
}>;
total: number;
page: number;
pageSize: number;
}> {
return http.get('/v1/teacher/students', {
params: {
pageNum: params?.pageNum,
pageSize: params?.pageSize,
keyword: params?.keyword,
},
}) as any;
}
// 获取班级学生列表
// 后端返回 { list, total, pageNum, pageSize, classInfo },前端统一为 { items, total, page, pageSize, class }
export function getTeacherClassStudents(classId: number, params?: { pageNum?: number; pageSize?: number; keyword?: string }): Promise<{
items: Array<{
id: number;
name: string;
gender?: string;
birthDate?: string;
parentName?: string;
parentPhone?: string;
lessonCount?: number;
readingCount?: number;
createdAt: string;
}>;
total: number;
page: number;
pageSize: number;
class?: {
id: number;
name: string;
grade: string;
studentCount: number;
lessonCount: number;
};
}> {
return http.get(`/v1/teacher/classes/${classId}/students`, {
params: {
pageNum: params?.pageNum,
pageSize: params?.pageSize,
keyword: params?.keyword,
},
}).then((res: any) => ({
items: res?.list ?? res?.items ?? [],
total: res?.total ?? 0,
page: res?.pageNum ?? res?.page ?? 1,
pageSize: res?.pageSize ?? 10,
class: res?.classInfo ?? res?.class,
}));
}
// 获取班级教师列表
export function getClassTeachers(classId: number): Promise<TeacherClassTeacher[]> {
return http.get(`/v1/teacher/classes/${classId}/teachers`) as any;
}
// ==================== 授课记录 API ====================
export interface CreateLessonDto {
courseId: number | string; // string 避免 Long 精度丢失
classId: number;
teacherId: number;
title: string;
lessonDate: string; // YYYY-MM-DD
startTime?: string; // HH:mm
endTime?: string;
plannedDatetime?: string; // 兼容:前端可传此字段,由 adapter 转换为 lessonDate+startTime
}
export interface FinishLessonDto {
overallRating?: string;
participationRating?: string;
completionNote?: string;
actualDuration?: number;
}
export interface StudentRecordDto {
focus?: number;
participation?: number;
interest?: number;
understanding?: number;
notes?: string;
}
// 后端状态值: scheduled, in_progress, completed, cancelled
const STATUS_TO_BACKEND: Record<string, string> = {
PLANNED: 'scheduled',
IN_PROGRESS: 'in_progress',
COMPLETED: 'completed',
CANCELLED: 'cancelled',
};
// 获取授课记录列表
export function getLessons(params?: {
pageNum?: number;
page?: number;
pageSize?: number;
status?: string;
startDate?: string;
endDate?: string;
}): Promise<{
items: any[];
total: number;
page: number;
pageSize: number;
}> {
const pageNum = params?.pageNum ?? params?.page ?? 1;
const status = params?.status ? (STATUS_TO_BACKEND[params.status] || params.status) : undefined;
return http
.get<{ list?: any[]; records?: any[]; total?: number | string; pageNum?: number; pageSize?: number }>(
'/v1/teacher/lessons',
{
params: {
pageNum,
pageSize: params?.pageSize ?? 10,
status,
startDate: params?.startDate,
endDate: params?.endDate,
},
}
)
.then((res) => {
const list = res?.list ?? res?.records ?? [];
return {
items: Array.isArray(list) ? list : [],
total: typeof res?.total === 'string' ? parseInt(res.total, 10) || 0 : (res?.total ?? 0),
page: res?.pageNum ?? pageNum,
pageSize: res?.pageSize ?? 10,
};
});
}
// 获取单个授课记录详情id 使用 string 避免 Long 精度丢失)
export function getLesson(id: number | string): Promise<any> {
return http.get(`/v1/teacher/lessons/${id}`) as any;
}
// 创建授课记录(备课)
export function createLesson(data: CreateLessonDto): Promise<any> {
return http.post('/v1/teacher/lessons', data) as any;
}
/** 从排课开始上课:创建课时并开始,适用于课表/排课详情的「开始上课」按钮 */
export function startLessonFromSchedule(schedulePlanId: number): Promise<{ id: number }> {
return http.post(`/v1/teacher/lessons/from-schedule/${schedulePlanId}/start`) as any;
}
// 开始上课id 使用 string 避免 Long 精度丢失)
export function startLesson(id: number | string): Promise<any> {
return http.post(`/v1/teacher/lessons/${id}/start`) as any;
}
// 结束上课id 使用 string 避免 Long 精度丢失)
export function finishLesson(id: number | string, data: FinishLessonDto): Promise<any> {
return http.post(`/v1/teacher/lessons/${id}/complete`, data) as any;
}
// 取消课程id 使用 string 避免 Long 精度丢失)
export function cancelLesson(id: number | string): Promise<any> {
return http.post(`/v1/teacher/lessons/${id}/cancel`) as any;
}
// 保存学生评价记录lessonId 使用 string 避免 Long 精度丢失)
export function saveStudentRecord(
lessonId: number | string,
studentId: number,
data: StudentRecordDto
): Promise<any> {
return http.post(`/v1/teacher/lessons/${lessonId}/students/${studentId}/record`, data) as any;
}
// 获取课程所有学生记录
export interface StudentWithRecord {
id: number;
name: string;
gender?: string;
record: {
id: number;
focus?: number;
participation?: number;
interest?: number;
understanding?: number;
notes?: string;
} | null;
}
export interface StudentRecordsResponse {
lesson: {
id: number;
status: string;
className: string;
};
students: StudentWithRecord[];
}
export function getStudentRecords(lessonId: number | string): Promise<StudentRecordsResponse> {
return http.get(`/v1/teacher/lessons/${lessonId}/students/records`) as any;
}
// 批量保存学生评价记录lessonId 使用 string 避免 Long 精度丢失)
export function batchSaveStudentRecords(
lessonId: number | string,
records: Array<{ studentId: number } & StudentRecordDto>
): Promise<{ count: number; records: any[] }> {
return http.post(`/v1/teacher/lessons/${lessonId}/students/batch-records`, { records }) as any;
}
// ==================== 教师首页 API ====================
export interface DashboardData {
stats: {
classCount: number;
studentCount: number;
lessonCount: number;
courseCount: number;
};
todayLessons: Array<{
id: number;
courseId: number;
courseName: string;
pictureBookName?: string;
classId: number;
className: string;
plannedDatetime: string;
status: string;
duration: number;
}>;
recommendedCourses: Array<{
id: number;
name: string;
pictureBookName?: string;
coverImagePath?: string;
duration: number;
usageCount: number;
avgRating: number;
gradeTags: string[];
}>;
weeklyStats: {
lessonCount: number;
studentParticipation: number;
avgRating: number;
totalDuration: number;
};
recentActivities: Array<{
id: number;
type: string;
description: string;
time: string;
}>;
}
export const getTeacherDashboard = () =>
http.get('/v1/teacher/dashboard') as any;
export const getTodayLessons = () =>
http.get('/v1/teacher/today-lessons') as any;
export const getRecommendedCourses = () =>
http.get('/v1/teacher/recommended-courses') as any;
export const getWeeklyStats = () =>
http.get('/v1/teacher/weekly-stats') as any;
// ==================== 教师统计趋势 ====================
export interface TeacherLessonTrendItem {
month: string;
lessonCount: number;
avgRating: number;
}
export interface TeacherCourseUsageItem {
name: string;
value: number;
}
export const getTeacherLessonTrend = (months?: number) => {
return http.get('/v1/teacher/lesson-trend', { params: { months } }) as any;
};
export const getTeacherCourseUsage = () =>
http.get('/v1/teacher/course-usage') as any;
// ==================== 课程反馈 API ====================
export interface FeedbackDto {
designQuality?: number;
participation?: number;
goalAchievement?: number;
stepFeedbacks?: any;
pros?: string;
suggestions?: string;
activitiesDone?: any;
}
export interface LessonFeedback {
id: number;
lessonId: number;
teacherId: number;
designQuality?: number;
participation?: number;
goalAchievement?: number;
stepFeedbacks?: any;
pros?: string;
suggestions?: string;
activitiesDone?: any;
createdAt: string;
updatedAt: string;
teacher?: {
id: number;
name: string;
};
lesson?: {
id: number;
startDatetime?: string;
course: {
id: number;
name: string;
pictureBookName?: string;
};
class: {
id: number;
name: string;
};
};
}
// 提交课程反馈
export function submitFeedback(lessonId: number, data: FeedbackDto): Promise<LessonFeedback> {
return http.post(`/v1/teacher/lessons/${lessonId}/feedback`, data) as any;
}
// 获取课程反馈
export function getFeedback(lessonId: number): Promise<LessonFeedback | null> {
return http.get(`/v1/teacher/lessons/${lessonId}/feedback`) as any;
}
// ==================== 学校端反馈 API ====================
export interface FeedbackQueryParams {
pageNum?: number;
pageSize?: number;
teacherId?: number;
courseId?: number;
}
export interface FeedbackStats {
totalFeedbacks: number;
avgDesignQuality: number;
avgParticipation: number;
avgGoalAchievement: number;
courseStats: Record<number, { count: number; avgRating: number }>;
}
// 获取学校端反馈列表
export function getSchoolFeedbacks(params: FeedbackQueryParams): Promise<{
list: LessonFeedback[];
total: number;
pageNum: number;
pageSize: number;
}> {
return http.get<{ list: LessonFeedback[]; total: number; pageNum: number; pageSize: number }>('/v1/school/feedbacks', {
params: {
pageNum: params.pageNum,
pageSize: params.pageSize,
teacherId: params.teacherId,
courseId: params.courseId,
},
});
}
// 获取反馈统计
export function getFeedbackStats(): Promise<FeedbackStats> {
return http.get<FeedbackStats>('/v1/school/feedbacks/stats');
}
// 获取教师自己的反馈列表
export function getTeacherFeedbacks(params: FeedbackQueryParams): Promise<{
items: LessonFeedback[];
total: number;
page: number;
pageSize: number;
}> {
// 直接使用 http 调用后端 API
return http.get<{ list: LessonFeedback[]; total: number; pageNum: number; pageSize: number }>('/v1/teacher/feedbacks', {
params: {
pageNum: params.pageNum,
pageSize: params.pageSize,
},
}).then(res => ({
items: res.list || res.records || [],
total: res.total || 0,
page: res.pageNum || 1,
pageSize: res.pageSize || 10,
}));
}
// 获取教师自己的反馈统计
export function getTeacherFeedbackStats(): Promise<FeedbackStats> {
return http.get<{
totalFeedbacks: number;
avgDesignQuality: number;
avgParticipation: number;
avgGoalAchievement: number;
byType: Record<string, number>;
}>('/v1/teacher/feedbacks/stats').then(res => ({
totalFeedbacks: res.totalFeedbacks || 0,
avgDesignQuality: res.avgDesignQuality || 0,
avgParticipation: res.avgParticipation || 0,
avgGoalAchievement: res.avgGoalAchievement || 0,
courseStats: res.byType || {},
}));
}
// ==================== 课程进度追踪 API ====================
export interface LessonProgress {
id: number;
lessonIds: number[];
completedLessonIds: number[];
currentLessonId?: number;
currentStepId?: number;
progressData: any;
}
export interface SaveLessonProgressDto {
lessonIds?: number[];
completedLessonIds?: number[];
currentLessonId?: number;
currentStepId?: number;
progressData?: any;
}
// 保存课程进度lessonId 使用 string 避免 Long 精度丢失)
export function saveLessonProgress(lessonId: number | string, data: SaveLessonProgressDto): Promise<LessonProgress> {
return http.put(`/v1/teacher/lessons/${lessonId}/progress`, data) as any;
}
// 获取课程进度lessonId 使用 string 避免 Long 精度丢失)
export function getLessonProgress(lessonId: number | string): Promise<LessonProgress> {
return http.get(`/v1/teacher/lessons/${lessonId}/progress`) as any;
}
// ==================== 排课管理 API ====================
export interface TeacherSchedule {
id: number;
classId: number;
className?: string;
courseId: number;
courseName?: string;
coursePackageName?: string; // 课程包名称,与 courseName 二选一展示
lessonType?: string; // 课程类型代码
lessonTypeName?: string; // 课程类型名称(后端已翻译)
teacherId?: number;
scheduledDate?: string;
scheduledTime?: string;
weekDay?: number;
repeatType: 'NONE' | 'DAILY' | 'WEEKLY';
source: 'SCHOOL' | 'TEACHER';
status: 'ACTIVE' | 'CANCELLED';
note?: string;
hasLesson: boolean;
lessonId?: number;
lessonStatus?: string;
createdAt: string;
}
export interface CreateTeacherScheduleDto {
name: string; // 计划名称,与学校端 SchedulePlanCreateRequest 一致
classId: number;
courseId: number;
coursePackageId?: number; // 课程包 ID
lessonType?: string; // 课程类型 (INTRODUCTION/COLLECTIVE/LANGUAGE 等)
scheduledDate?: string;
scheduledTime?: string;
weekDay?: number;
repeatType?: 'NONE' | 'DAILY' | 'WEEKLY';
repeatEndDate?: string;
note?: string;
}
export interface TeacherTimetableItem {
date: string;
weekDay: number;
schedules: TeacherSchedule[];
}
export const getTeacherSchedules = (params?: {
startDate?: string;
endDate?: string;
status?: string;
pageNum?: number;
pageSize?: number;
}) => {
return http.get<{ list: TeacherSchedule[]; total: number }>('/v1/teacher/schedules', { params })
.then(res => ({
list: res.list || res.records || [],
total: res.total || 0,
}));
};
export const getTeacherTimetable = (params: { startDate: string; endDate: string }) => {
return http.get<any[]>('/v1/teacher/schedules/timetable', { params })
.then(res => {
// 后端返回的是数组格式或包含 schedules 的对象
if (Array.isArray(res)) {
return res;
}
return res?.schedules || res?.data || [];
});
};
export const getTodayTeacherSchedules = () =>
http.get<TeacherSchedule[]>('/v1/teacher/schedules/today');
export const createTeacherSchedule = (data: CreateTeacherScheduleDto) =>
http.post<TeacherSchedule>('/v1/teacher/schedules', data);
export const updateTeacherSchedule = (id: number, data: Partial<CreateTeacherScheduleDto> & { status?: string }) =>
http.put<TeacherSchedule>(`/v1/teacher/schedules/${id}`, data);
export const cancelTeacherSchedule = (id: number) =>
http.delete<{ message: string }>(`/v1/teacher/schedules/${id}`);
// ==================== 阅读任务 API ====================
export interface TeacherTask {
id: number;
tenantId: number;
title: string;
description?: string;
taskType: 'READING' | 'ACTIVITY' | 'HOMEWORK';
targetType: 'CLASS' | 'STUDENT';
status: 'DRAFT' | 'PUBLISHED' | 'ARCHIVED';
relatedCourseId?: number;
relatedBookName?: string; // 关联绘本名称
startDate: string;
endDate: string;
createdBy: number;
createdAt: string;
updatedAt: string;
course?: {
id: number;
name: string;
};
targetCount?: number;
completionCount?: number;
}
export interface TaskCompletion {
id: number;
taskId: number;
studentId: number;
status: 'PENDING' | 'SUBMITTED' | 'REVIEWED';
statusText?: string;
photos?: string[];
videoUrl?: string;
audioUrl?: string;
content?: string;
parentFeedback?: string; // 家长反馈(兼容旧字段)
submittedAt?: string;
reviewedAt?: string;
completedAt?: string; // 完成时间(兼容旧字段)
createdAt: string;
student: {
id: number;
name: string;
avatar?: string;
gender?: string;
class?: {
id: number;
name: string;
grade?: string;
};
classInfo?: {
id: number;
name: string;
grade?: string;
};
};
feedback?: TaskFeedback;
}
export interface TaskFeedback {
id: number;
completionId: number;
result: 'EXCELLENT' | 'PASSED' | 'NEEDS_WORK';
resultText?: string;
rating?: number;
comment?: string;
teacherId?: number;
teacherName?: string;
teacherAvatar?: string;
createdAt?: string;
}
export interface CreateTeacherTaskDto {
title: string;
description?: string;
taskType: 'READING' | 'ACTIVITY' | 'HOMEWORK';
targetType: 'CLASS' | 'STUDENT';
targetIds: number[];
relatedCourseId?: number;
relatedBookName?: string; // 关联绘本名称
startDate: string;
endDate: string;
}
export interface TaskFeedbackDto {
result: 'EXCELLENT' | 'PASSED' | 'NEEDS_WORK';
rating?: number;
comment?: string;
}
export interface UpdateTaskCompletionDto {
status: 'PENDING' | 'IN_PROGRESS' | 'COMPLETED';
feedback?: string;
}
// 获取教师任务列表
export const getTeacherTasks = (params?: { pageNum?: number; pageSize?: number; keyword?: string; type?: string; status?: string }) =>
http.get<{ list: any[]; total: number; pageNum: number; pageSize: number }>('/v1/teacher/tasks', { params })
.then(res => ({
items: res.list || [],
total: res.total || 0,
page: res.pageNum || 1,
pageSize: res.pageSize || 10,
}));
export const getTeacherTask = (id: number) =>
http.get(`/v1/teacher/tasks/${id}`) as any;
// 获取任务完成情况列表(新版,支持分页和状态筛选)
export const getTeacherTaskCompletions = (taskId: number, params?: {
pageNum?: number;
pageSize?: number;
status?: string;
}) =>
http.get<{ list: any[]; total: number; pageNum: number; pageSize: number }>(
`/v1/teacher/tasks/${taskId}/completions`,
{ params }
).then(res => ({
items: res.list || [],
total: res.total || 0,
page: res.pageNum || 1,
pageSize: res.pageSize || 10,
}));
// 获取提交详情
export const getCompletionDetail = (completionId: number) =>
http.get<TaskCompletion>(`/v1/teacher/tasks/completions/${completionId}`) as any;
// 提交评价
export const submitCompletionFeedback = (completionId: number, data: TaskFeedbackDto) =>
http.post<TaskFeedback>(`/v1/teacher/tasks/completions/${completionId}/feedback`, data) as any;
// 修改评价
export const updateCompletionFeedback = (completionId: number, data: TaskFeedbackDto) =>
http.put<TaskFeedback>(`/v1/teacher/tasks/completions/${completionId}/feedback`, data) as any;
export const createTeacherTask = (data: CreateTeacherTaskDto) =>
http.post('/v1/teacher/tasks', data) as any;
export const updateTeacherTask = (id: number, data: Partial<CreateTeacherTaskDto> & { status?: string }) =>
http.put(`/v1/teacher/tasks/${id}`, data) as any;
export const deleteTeacherTask = (id: number) =>
http.delete(`/v1/teacher/tasks/${id}`) as any;
// 兼容旧代码的函数
export const updateTaskCompletion = (_taskId: number, _studentId: number, _data: UpdateTaskCompletionDto) =>
Promise.reject(new Error('请使用 submitCompletionFeedback 或 updateCompletionFeedback'));
export const sendTaskReminder = (_taskId: number) =>
http.post(`/v1/teacher/tasks/${_taskId}/remind`) as any;
// ==================== 任务模板 API ====================
export interface TaskTemplate {
id: number;
tenantId: number;
name: string;
description?: string;
taskType: 'READING' | 'ACTIVITY' | 'HOMEWORK';
relatedCourseId?: number;
defaultDuration: number;
isDefault: boolean;
status: string;
createdBy: number;
createdAt: string;
updatedAt: string;
course?: {
id: number;
name: string;
pictureBookName?: string;
};
}
export interface CreateTaskTemplateDto {
name: string;
description?: string;
taskType: 'READING' | 'ACTIVITY' | 'HOMEWORK';
relatedCourseId?: number;
defaultDuration?: number;
isDefault?: boolean;
}
export interface CreateTaskFromTemplateDto {
templateId: number;
targetIds: number[];
targetType: 'CLASS' | 'STUDENT';
startDate?: string;
}
export const getTaskTemplates = (params?: { pageNum?: number; pageSize?: number }) =>
http.get<{ list: any[]; total: number }>('/v1/teacher/task-templates', { params })
.then(res => ({
items: res.list || [],
total: res.total || 0,
}));
export const getTaskTemplate = (id: number) =>
http.get(`/v1/teacher/task-templates/${id}`) as any;
export const getDefaultTaskTemplate = (taskType: string) =>
http.get('/v1/teacher/task-templates/default', { params: { taskType } }) as any;
export const createTaskFromTemplate = (data: CreateTaskFromTemplateDto) =>
http.post('/v1/teacher/tasks/from-template', data) as any;
// ==================== 任务统计 API ====================
export interface TaskStats {
totalTasks: number;
publishedTasks: number;
completedTasks: number;
inProgressTasks: number;
pendingCount: number;
totalCompletions: number;
completionRate: number;
}
export interface TaskStatsByType {
[key: string]: {
total: number;
completed: number;
rate: number;
};
}
export interface TaskStatsByClass {
classId: number;
className: string;
grade: string;
total: number;
completed: number;
rate: number;
}
export interface MonthlyTaskStats {
month: string;
tasks: number;
completions: number;
completed: number;
rate: number;
}
export const getTaskStats = () =>
http.get('/v1/teacher/tasks/stats') as any;
export const getTaskStatsByType = () =>
http.get('/v1/teacher/tasks/stats/by-type') as any;
export const getTaskStatsByClass = () =>
http.get('/v1/teacher/tasks/stats/by-class') as any;
export const getMonthlyTaskStats = (months?: number) => {
return http.get('/v1/teacher/tasks/stats/monthly', { params: { months } }) as any;
};