kindergarten_java/reading-platform-frontend/src/api/school.ts
En 6e11c874d2 chore: 忽略 target 目录和 .class 文件
- 添加 target/ 到 .gitignore
- 从 git 暂存区移除已追踪的 target 目录

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 16:50:54 +08:00

1030 lines
27 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';
// ==================== 类型定义 ====================
export interface TeacherQueryParams {
pageNum?: number;
pageSize?: number;
keyword?: string;
status?: string;
}
export interface Teacher {
id: number;
name: string;
phone: string;
email?: string;
loginAccount: string;
status: string;
classIds: number[];
classNames?: string | string[];
lessonCount?: number;
createdAt: string;
}
export interface CreateTeacherDto {
name: string;
phone: string;
email?: string;
loginAccount: string;
password?: string;
classIds?: number[];
}
export interface StudentQueryParams {
pageNum?: number;
pageSize?: number;
classId?: number;
keyword?: string;
}
export interface Student {
id: number;
name: string;
gender?: string;
birthDate?: string;
classId: number;
className?: string;
parentName?: string;
parentPhone?: string;
lessonCount?: number;
readingCount?: number;
avgScore?: number;
createdAt: string;
}
export interface CreateStudentDto {
name: string;
gender?: string;
birthDate?: string;
classId: number;
parentName?: string;
parentPhone?: string;
}
export interface ClassInfo {
id: number;
name: string;
grade: string;
teacherId?: number;
teacherName?: string;
studentCount: number;
lessonCount: number;
createdAt?: string;
teachers?: ClassTeacher[]; // 新增:教师团队
}
export interface ClassTeacher {
id: number;
teacherId: number;
teacherName: string;
teacherPhone?: string;
teacherEmail?: string;
role: 'MAIN' | 'ASSIST' | 'CARE';
isPrimary: boolean;
createdAt?: string;
}
export interface AddClassTeacherDto {
teacherId: number;
role: 'MAIN' | 'ASSIST' | 'CARE';
isPrimary?: boolean;
}
export interface UpdateClassTeacherDto {
role?: 'MAIN' | 'ASSIST' | 'CARE';
isPrimary?: boolean;
}
export interface TransferStudentDto {
toClassId: number;
reason?: string;
}
export interface StudentClassHistory {
id: number;
fromClass: { id: number; name: string; grade: string } | null;
toClass: { id: number; name: string; grade: string };
reason?: string;
operatedBy?: number;
createdAt: string;
}
export interface CreateClassDto {
name: string;
grade: string;
teacherId?: number;
}
export interface SchoolStats {
teacherCount: number;
studentCount: number;
classCount: number;
lessonCount: number;
}
export interface PackageInfo {
packageType: string;
teacherQuota: number;
studentQuota: number;
storageQuota: number;
teacherCount: number;
studentCount: number;
storageUsed: number;
startDate: string;
expireDate: string;
status: string;
}
export interface PackageUsage {
teacher: {
used: number;
quota: number;
percentage: number;
};
student: {
used: number;
quota: number;
percentage: number;
};
storage: {
used: number;
quota: number;
percentage: number;
};
}
// ==================== 教师管理 ====================
export const getTeachers = (params: TeacherQueryParams) =>
http.get<{ list: Teacher[]; total: number; pageNum: number; pageSize: number; pages: number }>('/v1/school/teachers', { params });
export const getTeacher = (id: number) =>
http.get<Teacher>(`/v1/school/teachers/${id}`);
export const createTeacher = (data: CreateTeacherDto) =>
http.post<Teacher>('/v1/school/teachers', data);
export const updateTeacher = (id: number, data: Partial<CreateTeacherDto>) =>
http.put<Teacher>(`/v1/school/teachers/${id}`, data);
export const deleteTeacher = (id: number) =>
http.delete(`/v1/school/teachers/${id}`);
export const resetTeacherPassword = (id: number) =>
http.post<{ tempPassword: string }>(`/v1/school/teachers/${id}/reset-password`);
// ==================== 学生管理 ====================
export const getStudents = (params: StudentQueryParams) =>
http.get<{ list: Student[]; total: number; pageNum: number; pageSize: number; pages: number }>('/v1/school/students', { params });
export const getStudent = (id: number) =>
http.get<Student>(`/v1/school/students/${id}`);
export const createStudent = (data: CreateStudentDto) =>
http.post<Student>('/v1/school/students', data);
export const updateStudent = (id: number, data: Partial<CreateStudentDto>) =>
http.put<Student>(`/v1/school/students/${id}`, data);
export const deleteStudent = (id: number) =>
http.delete(`/v1/school/students/${id}`);
// ==================== 学生批量导入 ====================
export interface ImportResult {
success: number;
failed: number;
errors: Array<{ row: number; message: string }>;
}
export interface ImportTemplate {
headers: string[];
example: string[];
notes: string[];
}
export const getStudentImportTemplate = () =>
http.get<ImportTemplate>('/v1/school/students/import/template');
export const importStudents = (file: File, defaultClassId?: number): Promise<ImportResult> => {
const formData = new FormData();
formData.append('file', file);
const params = defaultClassId ? { defaultClassId } : {};
return http.post('/v1/school/students/import', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
params,
});
};
// ==================== 班级管理 ====================
export const getClasses = () =>
http.get<{ list: ClassInfo[]; total: number }>('/v1/school/classes').then(res => res.list);
export const getClass = (id: number) =>
http.get<ClassInfo>(`/v1/school/classes/${id}`);
export const createClass = (data: CreateClassDto) =>
http.post<ClassInfo>('/v1/school/classes', data);
export const updateClass = (id: number, data: Partial<CreateClassDto>) =>
http.put<ClassInfo>(`/v1/school/classes/${id}`, data);
export const deleteClass = (id: number) =>
http.delete(`/v1/school/classes/${id}`);
export const getClassStudents = (classId: number, params?: { pageNum?: number; pageSize?: number; keyword?: string }) =>
http.get<{ list: Student[]; total: number; pageNum: number; pageSize: number; pages: number; class?: ClassInfo }>(`/v1/school/classes/${classId}/students`, { params });
// ==================== 统计数据 ====================
export const getSchoolStats = () =>
http.get<SchoolStats>('/v1/school/stats');
export const getActiveTeachers = (limit?: number) =>
http.get<Array<{ id: number; name: string; lessonCount: number }>>('/v1/school/stats/teachers', { params: { limit } });
export const getCourseUsageStats = () =>
http.get<Array<{ courseId: number; courseName: string; usageCount: number }>>('/v1/school/stats/courses');
export const getRecentActivities = (limit?: number) =>
http.get<Array<{ id: number; type: string; title: string; time: string }>>('/v1/school/stats/activities', { params: { limit } });
// ==================== 套餐信息旧API保留兼容 ====================
export const getPackageInfo = () =>
http.get<PackageInfo>('/v1/school/package');
export const getPackageUsage = () =>
http.get<PackageUsage>('/v1/school/package/usage');
// ==================== 套餐管理新API ====================
export interface TenantPackage {
id: number;
tenantId: number;
packageId: number;
startDate: string;
endDate: string;
status: 'ACTIVE' | 'EXPIRED' | 'CANCELLED';
pricePaid?: number;
createdAt: string;
package: {
id: number;
name: string;
description?: string;
price: number;
discountPrice?: number;
courseCount: number;
gradeLevels: string;
status: string;
courses: Array<{
id: number;
packageId: number;
courseId: number;
gradeLevel: string;
course: {
id: number;
name: string;
coverImagePath?: string;
};
}>;
};
}
export interface RenewPackageDto {
endDate: string;
pricePaid?: number;
}
export const getTenantPackages = () =>
http.get<TenantPackage[]>('/v1/school/packages');
export const renewPackage = (packageId: number, data: RenewPackageDto) =>
http.post<TenantPackage>(`/v1/school/packages/${packageId}/renew`, data);
// ==================== 系统设置 ====================
export interface SystemSettings {
id: number;
tenantId: number;
schoolName?: string;
schoolLogo?: string;
address?: string;
notifyOnLesson: boolean;
notifyOnTask: boolean;
notifyOnGrowth: boolean;
createdAt: string;
updatedAt: string;
}
export interface UpdateSettingsDto {
schoolName?: string;
schoolLogo?: string;
address?: string;
notifyOnLesson?: boolean;
notifyOnTask?: boolean;
notifyOnGrowth?: boolean;
}
export const getSettings = () =>
http.get<SystemSettings>('/v1/school/settings');
export const updateSettings = (data: UpdateSettingsDto) =>
http.put<SystemSettings>('/v1/school/settings', data);
// ==================== 课程管理 ====================
export const getSchoolCourses = () =>
http.get<any[]>('/v1/school/courses');
export const getSchoolCourse = (id: number) =>
http.get<any>(`/v1/school/courses/${id}`);
// ==================== 班级教师管理 ====================
export const getClassTeachers = (classId: number) =>
http.get<ClassTeacher[]>(`/v1/school/classes/${classId}/teachers`);
export const addClassTeacher = (classId: number, data: AddClassTeacherDto) =>
http.post<ClassTeacher>(`/v1/school/classes/${classId}/teachers`, data);
export const updateClassTeacher = (classId: number, teacherId: number, data: UpdateClassTeacherDto) =>
http.put<ClassTeacher>(`/v1/school/classes/${classId}/teachers/${teacherId}`, data);
export const removeClassTeacher = (classId: number, teacherId: number) =>
http.delete<{ message: string }>(`/v1/school/classes/${classId}/teachers/${teacherId}`);
// ==================== 学生调班 ====================
export const transferStudent = (studentId: number, data: TransferStudentDto) =>
http.post<{ message: string }>(`/v1/school/students/${studentId}/transfer`, data);
export const getStudentClassHistory = (studentId: number) =>
http.get<StudentClassHistory[]>(`/v1/school/students/${studentId}/history`);
// ==================== 排课管理 ====================
export interface SchedulePlan {
id: number;
tenantId: number;
classId: number;
className: string;
courseId: number;
courseName: string;
teacherId?: number;
teacherName?: string;
scheduledDate?: string;
scheduledTime?: string;
weekDay?: number;
repeatType: 'NONE' | 'DAILY' | 'WEEKLY';
repeatEndDate?: string;
source: 'SCHOOL' | 'TEACHER';
status: 'ACTIVE' | 'CANCELLED';
note?: string;
createdBy: number;
createdAt: string;
updatedAt: string;
}
export interface CreateScheduleDto {
classId: number;
courseId: number;
teacherId?: number;
scheduledDate?: string;
scheduledTime?: string;
weekDay?: number;
repeatType: 'NONE' | 'DAILY' | 'WEEKLY';
repeatEndDate?: string;
note?: string;
}
export interface UpdateScheduleDto {
teacherId?: number;
scheduledDate?: string;
scheduledTime?: string;
weekDay?: number;
repeatType?: 'NONE' | 'DAILY' | 'WEEKLY';
repeatEndDate?: string;
note?: string;
status?: string;
}
export interface ScheduleQueryParams {
classId?: number;
teacherId?: number;
courseId?: number;
startDate?: string;
endDate?: string;
status?: string;
source?: string;
pageNum?: number;
pageSize?: number;
}
export interface TimetableItem {
date: string;
weekDay: number;
schedules: SchedulePlan[];
}
export interface TimetableQueryParams {
startDate: string;
endDate: string;
classId?: number;
teacherId?: number;
}
export const getSchedules = (params?: ScheduleQueryParams) =>
http.get<{ list: SchedulePlan[]; total: number; pageNum: number; pageSize: number; pages: number }>('/v1/school/schedules', { params });
export const getSchedule = (id: number) =>
http.get<SchedulePlan>(`/v1/school/schedules/${id}`);
export const createSchedule = (data: CreateScheduleDto) =>
http.post<SchedulePlan>('/v1/school/schedules', data);
export const updateSchedule = (id: number, data: UpdateScheduleDto) =>
http.put<SchedulePlan>(`/v1/school/schedules/${id}`, data);
export const cancelSchedule = (id: number) =>
http.delete<{ message: string }>(`/v1/school/schedules/${id}`);
export const getTimetable = (params: TimetableQueryParams) =>
http.get<TimetableItem[]>('/v1/school/schedules/timetable', { params });
export interface BatchScheduleItem {
classId: number;
courseId: number;
teacherId?: number;
scheduledDate: string;
scheduledTime?: string;
note?: string;
}
export interface BatchCreateResult {
success: number;
failed: number;
results: SchedulePlan[];
errors: Array<{ index: number; message: string }>;
}
export const batchCreateSchedules = (schedules: BatchScheduleItem[]) =>
http.post<BatchCreateResult>('/v1/school/schedules/batch', { schedules });
// ==================== 趋势与分布统计 ====================
export interface LessonTrendItem {
month: string;
lessonCount: number;
studentCount: number;
}
export interface CourseDistributionItem {
name: string;
value: number;
}
export const getLessonTrend = (months?: number) =>
http.get<LessonTrendItem[]>('/v1/school/stats/lesson-trend', { params: { months } });
export const getCourseDistribution = () =>
http.get<CourseDistributionItem[]>('/v1/school/stats/course-distribution');
// ==================== 数据导出 ====================
export const exportLessons = (startDate?: string, endDate?: string) => {
const params = new URLSearchParams();
if (startDate) params.append('startDate', startDate);
if (endDate) params.append('endDate', endDate);
const token = localStorage.getItem('token');
const url = `/api/v1/school/export/lessons?${params.toString()}`;
return fetch(url, {
headers: {
Authorization: `Bearer ${token}`,
},
}).then((res) => {
if (!res.ok) throw new Error('导出失败');
return res.blob();
}).then((blob) => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `授课记录_${startDate || ''}_${endDate || ''}.xlsx`;
a.click();
window.URL.revokeObjectURL(url);
});
};
export const exportTeacherStats = (startDate?: string, endDate?: string) => {
const params = new URLSearchParams();
if (startDate) params.append('startDate', startDate);
if (endDate) params.append('endDate', endDate);
const token = localStorage.getItem('token');
const url = `/api/v1/school/export/teacher-stats?${params.toString()}`;
return fetch(url, {
headers: {
Authorization: `Bearer ${token}`,
},
}).then((res) => {
if (!res.ok) throw new Error('导出失败');
return res.blob();
}).then((blob) => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `教师绩效统计_${startDate || ''}_${endDate || ''}.xlsx`;
a.click();
window.URL.revokeObjectURL(url);
});
};
export const exportStudentStats = (classId?: number) => {
const params = new URLSearchParams();
if (classId) params.append('classId', String(classId));
const token = localStorage.getItem('token');
const url = `/api/v1/school/export/student-stats?${params.toString()}`;
return fetch(url, {
headers: {
Authorization: `Bearer ${token}`,
},
}).then((res) => {
if (!res.ok) throw new Error('导出失败');
return res.blob();
}).then((blob) => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `学生统计.xlsx`;
a.click();
window.URL.revokeObjectURL(url);
});
};
// ==================== 排课模板 ====================
export interface ScheduleTemplate {
id: number;
tenantId: number;
name: string;
courseId: number;
courseName?: string;
classId?: number;
className?: string;
teacherId?: number;
teacherName?: string;
scheduledTime?: string;
weekDay?: number;
duration: number;
isDefault: boolean;
createdAt: string;
updatedAt: string;
}
export interface CreateScheduleTemplateDto {
name: string;
courseId: number;
classId?: number;
teacherId?: number;
scheduledTime?: string;
weekDay?: number;
duration?: number;
isDefault?: boolean;
}
export interface UpdateScheduleTemplateDto {
name?: string;
classId?: number;
teacherId?: number;
scheduledTime?: string;
weekDay?: number;
duration?: number;
isDefault?: boolean;
}
export interface ApplyTemplateDto {
scheduledDate: string;
classId?: number;
teacherId?: number;
}
export const getScheduleTemplates = (params?: { classId?: number; courseId?: number }) =>
http.get<ScheduleTemplate[]>('/v1/school/schedule-templates', { params });
export const getScheduleTemplate = (id: number) =>
http.get<ScheduleTemplate>(`/v1/school/schedule-templates/${id}`);
export const createScheduleTemplate = (data: CreateScheduleTemplateDto) =>
http.post<ScheduleTemplate>('/v1/school/schedule-templates', data);
export const updateScheduleTemplate = (id: number, data: UpdateScheduleTemplateDto) =>
http.put<ScheduleTemplate>(`/v1/school/schedule-templates/${id}`, data);
export const deleteScheduleTemplate = (id: number) =>
http.delete<{ message: string }>(`/v1/school/schedule-templates/${id}`);
export const applyScheduleTemplate = (id: number, data: ApplyTemplateDto) =>
http.post<SchedulePlan>(`/v1/school/schedule-templates/${id}/apply`, data);
// ==================== 操作日志 ====================
export interface OperationLog {
id: number;
tenantId: number;
userId: number;
userType: string;
action: string;
module: string;
description: string;
targetId: number | null;
oldValue: string | null;
newValue: string | null;
ipAddress: string | null;
createdAt: string;
}
export interface OperationLogStats {
total: number;
modules: { name: string; count: number }[];
actions: { name: string; count: number }[];
}
export const getOperationLogs = (params?: {
pageNum?: number;
pageSize?: number;
module?: string;
action?: string;
startDate?: string;
endDate?: string;
}) => http.get<{ records: OperationLog[]; total: number; pageNum: number; pageSize: number; pages: number }>(
'/v1/school/operation-logs',
{ params }
).then(res => ({
list: res.records || [],
total: res.total || 0,
pageNum: res.pageNum || 1,
pageSize: res.pageSize || 10,
pages: res.pages || 0,
}));
export const getOperationLogStats = (startDate?: string, endDate?: string) =>
http.get<{ totalLogs: number; byModule: Record<string, number>; byOperator: Record<string, number> }>('/v1/school/operation-logs/stats', {
params: { startDate, endDate },
}).then(res => ({
totalLogs: res.totalLogs || 0,
byModule: res.byModule || {},
byOperator: res.byOperator || {},
}));
export const getOperationLogById = (id: number) =>
http.get<OperationLog>(`/v1/school/operation-logs/${id}`);
// ==================== 任务模板 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 UpdateTaskTemplateDto {
name?: string;
description?: string;
relatedCourseId?: number;
defaultDuration?: number;
isDefault?: boolean;
status?: string;
}
export const getTaskTemplates = (params?: {
pageNum?: number;
pageSize?: number;
taskType?: string;
keyword?: string;
}) => http.get<{ list: TaskTemplate[]; total: number; pageNum: number; pageSize: number; pages: number }>('/v1/school/task-templates', { params })
.then(res => ({
list: res.list || res.records || [],
total: res.total || 0,
pageNum: res.pageNum || 1,
pageSize: res.pageSize || 10,
pages: res.pages || 0,
}));
export const getTaskTemplate = (id: number) =>
http.get<TaskTemplate>(`/v1/school/task-templates/${id}`);
export const getDefaultTaskTemplate = (taskType: string) =>
http.get<TaskTemplate | null>(`/v1/school/task-templates/default/${taskType}`);
export const createTaskTemplate = (data: CreateTaskTemplateDto) =>
http.post<TaskTemplate>('/v1/school/task-templates', data);
export const updateTaskTemplate = (id: number, data: UpdateTaskTemplateDto) =>
http.put<TaskTemplate>(`/v1/school/task-templates/${id}`, data);
export const deleteTaskTemplate = (id: number) =>
http.delete<{ message: string }>(`/v1/school/task-templates/${id}`);
// ==================== 任务统计 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 = () =>
Promise.resolve({
totalTasks: 0,
publishedTasks: 0,
completedTasks: 0,
inProgressTasks: 0,
pendingCount: 0,
totalCompletions: 0,
completionRate: 0,
});
export const getTaskStatsByType = () =>
Promise.resolve({});
export const getTaskStatsByClass = () =>
Promise.resolve([]);
export const getMonthlyTaskStats = (_months?: number) =>
Promise.resolve([]);
// ==================== 任务管理 API ====================
export interface SchoolTask {
id: number;
tenantId: number;
title: string;
description?: string;
taskType: 'READING' | 'ACTIVITY' | 'HOMEWORK';
targetType: 'CLASS' | 'STUDENT';
relatedCourseId?: number;
course?: {
id: number;
name: string;
};
startDate: string;
endDate: string;
status: 'DRAFT' | 'PUBLISHED' | 'ARCHIVED';
createdBy: number;
targetCount?: number;
completionCount?: number;
createdAt: string;
updatedAt: string;
}
export interface TaskCompletion {
id: number;
taskId: number;
studentId: number;
studentName: string;
className: string;
status: 'PENDING' | 'IN_PROGRESS' | 'COMPLETED';
completedAt?: string;
parentFeedback?: string;
rating?: number;
}
export interface CreateSchoolTaskDto {
title: string;
description?: string;
taskType: 'READING' | 'ACTIVITY' | 'HOMEWORK';
targetType: 'CLASS' | 'STUDENT';
targetIds: number[];
relatedCourseId?: number;
startDate: string;
endDate: string;
}
export interface UpdateSchoolTaskDto {
title?: string;
description?: string;
taskType?: 'READING' | 'ACTIVITY' | 'HOMEWORK';
relatedCourseId?: number;
startDate?: string;
endDate?: string;
status?: 'DRAFT' | 'PUBLISHED' | 'ARCHIVED';
}
export const getSchoolTasks = (params?: {
pageNum?: number;
pageSize?: number;
status?: string;
taskType?: string;
keyword?: string;
}) => http.get<{ list: SchoolTask[]; total: number; pageNum: number; pageSize: number; pages: number }>('/v1/school/tasks', { params });
export const getSchoolTask = (id: number) =>
http.get<SchoolTask>(`/v1/school/tasks/${id}`);
export const createSchoolTask = (data: CreateSchoolTaskDto) =>
http.post<SchoolTask>('/v1/school/tasks', data);
export const updateSchoolTask = (id: number, data: UpdateSchoolTaskDto) =>
http.put<SchoolTask>(`/v1/school/tasks/${id}`, data);
export const deleteSchoolTask = (id: number) =>
http.delete<{ message: string }>(`/v1/school/tasks/${id}`);
export const getSchoolTaskCompletions = (taskId: number) =>
http.get<TaskCompletion[]>(`/v1/school/tasks/${taskId}/completions`);
export const getSchoolClasses = () =>
http.get<ClassInfo[]>('/v1/school/classes');
// ==================== 数据报告 API ====================
export interface ReportOverview {
totalLessons: number;
activeTeacherCount: number;
usedCourseCount: number;
avgRating: number;
}
export interface TeacherReport {
id: number;
name: string;
lessonCount: number;
courseCount: number;
feedbackCount: number;
avgRating: number;
}
export interface CourseReport {
id: number;
name: string;
lessonCount: number;
teacherCount: number;
studentCount: number;
avgRating: number;
}
export interface StudentReport {
id: number;
name: string;
className: string;
lessonCount: number;
avgFocus: number;
avgParticipation: number;
}
export const getReportOverview = () =>
http.get<ReportOverview>('/v1/school/reports/overview');
export const getTeacherReports = () =>
http.get<TeacherReport[]>('/v1/school/reports/teachers');
export const getCourseReports = () =>
http.get<CourseReport[]>('/v1/school/reports/courses');
export const getStudentReports = () =>
http.get<StudentReport[]>('/v1/school/reports/students');
// ==================== 家长管理 ====================
export interface ParentQueryParams {
pageNum?: number;
pageSize?: number;
keyword?: string;
status?: string;
}
export interface ParentChild {
id: number;
name: string;
relationship: string;
class?: {
id: number;
name: string;
};
}
export interface Parent {
id: number;
name: string;
phone: string;
email?: string;
loginAccount: string;
status: string;
tenantId: number;
childrenCount: number;
children?: ParentChild[];
createdAt: string;
}
export interface CreateParentDto {
name: string;
phone: string;
email?: string;
loginAccount: string;
password?: string;
}
export interface UpdateParentDto {
name?: string;
phone?: string;
email?: string;
}
export interface AddChildDto {
studentId: number;
relationship: string;
}
export const getParents = (params?: ParentQueryParams) =>
http.get<{ list: Parent[]; total: number; pageNum: number; pageSize: number; pages: number }>('/v1/school/parents', { params });
export const getParent = (id: number) =>
http.get<Parent>(`/v1/school/parents/${id}`);
export const createParent = (data: CreateParentDto) =>
http.post<Parent>('/v1/school/parents', data);
export const updateParent = (id: number, data: UpdateParentDto) =>
http.put<Parent>(`/v1/school/parents/${id}`, data);
export const deleteParent = (id: number) =>
http.delete<{ message: string }>(`/v1/school/parents/${id}`);
export const resetParentPassword = (id: number) =>
http.post<{ tempPassword: string }>(`/v1/school/parents/${id}/reset-password`);
export const getParentChildren = async (parentId: number): Promise<ParentChild[]> => {
const parent = await http.get<Parent & { children: ParentChild[] }>(`/v1/school/parents/${parentId}`);
return parent.children || [];
};
export const addChildToParent = (parentId: number, data: AddChildDto) =>
http.post<ParentChild>(`/v1/school/parents/${parentId}/children/${data.studentId}`, { relationship: data.relationship });
export const removeChildFromParent = (parentId: number, studentId: number) =>
http.delete<{ message: string }>(`/v1/school/parents/${parentId}/children/${studentId}`);