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(`/v1/school/teachers/${id}`); export const createTeacher = (data: CreateTeacherDto) => http.post('/v1/school/teachers', data); export const updateTeacher = (id: number, data: Partial) => http.put(`/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(`/v1/school/students/${id}`); export const createStudent = (data: CreateStudentDto) => http.post('/v1/school/students', data); export const updateStudent = (id: number, data: Partial) => http.put(`/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('/v1/school/students/import/template'); export const importStudents = (file: File, defaultClassId?: number): Promise => { 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(`/v1/school/classes/${id}`); export const createClass = (data: CreateClassDto) => http.post('/v1/school/classes', data); export const updateClass = (id: number, data: Partial) => http.put(`/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('/v1/school/stats'); export const getActiveTeachers = (limit?: number) => http.get>('/v1/school/stats/teachers', { params: { limit } }); export const getCourseUsageStats = () => http.get>('/v1/school/stats/courses'); export const getRecentActivities = (limit?: number) => http.get>('/v1/school/stats/activities', { params: { limit } }); // ==================== 套餐信息(旧 API,保留兼容) ==================== export const getPackageInfo = () => http.get('/v1/school/package'); export const getPackageUsage = () => http.get('/v1/school/package/usage'); // ==================== 套餐管理(两层结构) ==================== // 课程包项(对应后端 CourseCollectionResponse.CoursePackageItem / CoursePackageResponse) export interface CoursePackageItem { id: number | string; name: string; description?: string; gradeLevels: string[] | string; courseCount: number; sortOrder?: number; /** getPackagesByCollection 返回的课程包包含课程列表 */ courses?: Array<{ id: number; name: string; gradeLevel?: string; sortOrder?: number; scheduleRefData?: string; }>; } // 课程套餐(最上层,对应后端 CourseCollectionResponse) export interface CourseCollection { id: number | string; name: string; description?: string; price: number; discountPrice?: number; discountType?: string; gradeLevels: string[]; status: string; packageCount: number; createdAt: string; publishedAt?: string; submittedAt?: string; reviewedAt?: string; updatedAt?: string; startDate?: string; // 开始日期(租户套餐) endDate?: string; // 结束日期(租户套餐) packages?: CoursePackageItem[]; // 包含的课程包列表 } // 课程包(中间层,7 步流程创建的教学资源) export interface CoursePackage { id: number | string; name: string; description?: string; pictureBookName?: string; gradeTags?: string[]; gradeLevels?: string[]; status: string; courseCount: number; duration?: number; sortOrder?: number; courses?: Array<{ id: number; name: string; gradeLevel: string; sortOrder: number; scheduleRefData?: string; }>; } export interface RenewPackageDto { endDate: string; pricePaid?: number; } // 获取课程套餐列表(三层架构) export const getCourseCollections = () => http.get('/v1/school/packages'); // 获取课程套餐下的课程包列表(返回 CoursePackageItem 列表) export const getCourseCollectionPackages = (collectionId: number | string) => http.get(`/v1/school/packages/${collectionId}/packages`); // 续费课程套餐(三层架构) export const renewCollection = (collectionId: number, data: RenewPackageDto) => http.post(`/v1/school/packages/${collectionId}/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('/v1/school/settings'); export const updateSettings = (data: UpdateSettingsDto) => http.put('/v1/school/settings', data); // ==================== 课程管理 ==================== export interface Course { id: number; tenantId?: number; name: string; code?: string; description?: string; coverUrl?: string; coverImagePath?: string; pictureBookName?: string; category?: string; ageRange?: string; difficultyLevel?: string; durationMinutes?: number; duration?: number; objectives?: string; status: string; isSystem: number; version?: string; usageCount?: number; teacherCount?: number; gradeTags?: string[]; domainTags?: string[]; createdAt?: string; updatedAt?: string; publishedAt?: string; } export interface SchoolCourseQueryParams { keyword?: string; grade?: string; // 小班|中班|大班 domain?: string; // 健康|语言|社会|科学|艺术(传英文码) lessonType?: string; // INTRODUCTION|COLLECTIVE|LANGUAGE|HEALTH|SCIENCE|SOCIAL|ART } export const getSchoolCourses = (params?: SchoolCourseQueryParams) => http.get('/v1/school/courses', { params }); // 分页版本(用于课程管理页面) export const getSchoolCourseList = (params?: { pageNum?: number; pageSize?: number; keyword?: string; grade?: string; domain?: string; lessonType?: string; }) => http.get<{ list: Course[]; total: number; pageNum: number; pageSize: number; pages: number }>('/v1/school/courses', { params }); export const getSchoolCourse = (id: number) => http.get(`/v1/school/courses/${id}`); // ==================== 班级教师管理 ==================== export const getClassTeachers = (classId: number) => http.get(`/v1/school/classes/${classId}/teachers`); export const addClassTeacher = (classId: number, data: AddClassTeacherDto) => http.post(`/v1/school/classes/${classId}/teachers`, data); export const updateClassTeacher = (classId: number, teacherId: number, data: UpdateClassTeacherDto) => http.put(`/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(`/v1/school/students/${studentId}/history`); // ==================== 排课管理 ==================== // 课程类型枚举(与后端 LessonTypeEnum 对齐) export type LessonType = | 'INTRODUCTION' | 'INTRO' | 'COLLECTIVE' | 'LANGUAGE' | 'HEALTH' | 'SCIENCE' | 'SOCIAL' | 'SOCIETY' | 'ART' | 'DOMAIN_HEALTH' | 'DOMAIN_LANGUAGE' | 'DOMAIN_SOCIAL' | 'DOMAIN_SCIENCE' | 'DOMAIN_ART'; // 课程类型信息 export interface LessonTypeInfo { lessonType: string; lessonTypeName: string; count: number; } // 日历视图 - 每日排课项 export interface DayScheduleItem { id: number; className: string; coursePackageName: string; courseName?: string; // 兼容 coursePackageName 的别名 lessonType?: string; lessonTypeName: string; teacherName: string; scheduledTime: string; status: string; } // 日历视图响应 export interface CalendarViewResponse { startDate: string; endDate: string; schedules: Record; } // 批量创建排课请求(按班级) export interface CreateSchedulesByClassesDto { coursePackageId: number; courseId: number; lessonType: LessonType; classIds: number[]; teacherId: number; scheduledDate: string; scheduledTime: string; repeatType?: 'NONE' | 'WEEKLY' | 'BIWEEKLY'; repeatEndDate?: string; note?: string; } export interface SchedulePlan { id: number; tenantId: number; name?: string; classId: number; className?: string; courseId: number; courseName?: string; coursePackageId?: number; coursePackageName?: string; lessonType?: LessonType; lessonTypeName?: string; teacherId?: number; teacherName?: string; scheduledDate?: string; scheduledTime?: string; weekDay?: number; repeatType: 'NONE' | 'DAILY' | 'WEEKLY' | 'BIWEEKLY'; repeatEndDate?: string; source: 'SCHOOL' | 'TEACHER'; status: 'ACTIVE' | 'CANCELLED' | 'scheduled' | '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(`/v1/school/schedules/${id}`); export const createSchedule = (data: CreateScheduleDto) => http.post('/v1/school/schedules', data); export const updateSchedule = (id: number, data: UpdateScheduleDto) => http.put(`/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<{ byDate: Record; byWeekDay: Record; total: number; }>('/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('/v1/school/schedules/batch', { schedules }); // 获取课程包的课程类型列表 export const getCoursePackageLessonTypes = (coursePackageId: number) => http.get(`/v1/school/schedules/course-packages/${coursePackageId}/lesson-types`); // 批量创建排课(按班级) export const createSchedulesByClasses = (data: CreateSchedulesByClassesDto) => http.post('/v1/school/schedules/batch-by-classes', data); // 获取日历视图数据 export const getCalendarViewData = (params?: { startDate?: string; endDate?: string; classId?: number; teacherId?: number; }) => http.get('/v1/school/schedules/calendar', { params }); // ==================== 趋势与分布统计 ==================== export interface LessonTrendItem { month: string; lessonCount: number; studentCount: number; } export interface CourseDistributionItem { name: string; value: number; } export const getLessonTrend = (months?: number) => http.get('/v1/school/stats/lesson-trend', { params: { months } }); export const getCourseDistribution = () => http.get('/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('/v1/school/schedule-templates', { params }); export const getScheduleTemplate = (id: number) => http.get(`/v1/school/schedule-templates/${id}`); export const createScheduleTemplate = (data: CreateScheduleTemplateDto) => http.post('/v1/school/schedule-templates', data); export const updateScheduleTemplate = (id: number, data: UpdateScheduleTemplateDto) => http.put(`/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(`/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; byOperator: Record }>('/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(`/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 || [], total: res.total || 0, pageNum: res.pageNum || 1, pageSize: res.pageSize || 10, pages: res.pages || 0, })); export const getTaskTemplate = (id: number) => http.get(`/v1/school/task-templates/${id}`); export const getDefaultTaskTemplate = (taskType: string) => http.get(`/v1/school/task-templates/default/${taskType}`); export const createTaskTemplate = (data: CreateTaskTemplateDto) => http.post('/v1/school/task-templates', data); export const updateTaskTemplate = (id: number, data: UpdateTaskTemplateDto) => http.put(`/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 type TaskCompletionStatus = 'PENDING' | 'SUBMITTED' | 'REVIEWED'; // 评价结果 export type FeedbackResult = 'EXCELLENT' | 'PASSED' | 'NEEDS_WORK'; // 教师评价 export interface TaskTeacherFeedback { id: number; result: FeedbackResult; resultText?: string; rating?: number; comment?: string; createdAt: string; teacherName?: string; } // 任务完成记录(新设计) export interface TaskCompletionRecord { id: number; taskId: number; studentId: number; status: TaskCompletionStatus; statusText?: string; photos?: string[]; videoUrl?: string; audioUrl?: string; content?: string; submittedAt?: string; reviewedAt?: string; createdAt: string; student?: { id: number; name: string; avatar?: string; gender?: string; classInfo?: { id: number; name: string; grade?: string; }; }; feedback?: TaskTeacherFeedback; } export interface SchoolTask { id: number; tenantId: number; title: string; description?: string; taskType: 'READING' | 'ACTIVITY' | 'HOMEWORK'; targetType: 'CLASS' | 'STUDENT'; relatedCourseId?: number; relatedBookName?: string; course?: { id: number; name: string; }; startDate: string; endDate: string; status: 'DRAFT' | 'PUBLISHED' | 'ARCHIVED'; createdBy: number; creatorName?: string; 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 interface SchoolTaskQueryParams { pageNum?: number; pageSize?: number; keyword?: string; type?: string; status?: string; classIds?: number[]; teacherIds?: number[]; dateType?: 'startDate' | 'endDate' | 'deadline'; startDate?: string; endDate?: string; completionRate?: 'high' | 'medium' | 'low'; sortBy?: 'createdAt' | 'startDate' | 'endDate' | 'completionRate'; sortOrder?: 'asc' | 'desc'; } // ========== 新 API:只读接口 ========== // 获取学校端任务列表(只读,多维度筛选) export const getReadingTaskList = (params?: SchoolTaskQueryParams) => http.get<{ list: SchoolTask[]; total: number; pageNum: number; pageSize: number; pages: number }>('/v1/school/reading-tasks', { params }) .then(res => ({ items: res.list || [], total: res.total || 0, pageNum: res.pageNum || 1, pageSize: res.pageSize || 10, pages: res.pages || 0, })); // 获取任务详情(只读) export const getReadingTaskDetail = (taskId: number) => http.get(`/v1/school/reading-tasks/${taskId}`); // 获取任务完成情况列表 export const getReadingTaskCompletions = (taskId: number, params?: { pageNum?: number; pageSize?: number; status?: string; }) => http.get<{ list: TaskCompletionRecord[]; total: number; pageNum: number; pageSize: number }>( `/v1/school/reading-tasks/${taskId}/completions`, { params } ).then(res => ({ items: res.list || [], total: res.total || 0, pageNum: res.pageNum || 1, pageSize: res.pageSize || 10, })); // 获取学生提交详情 export const getCompletionDetail = (completionId: number) => http.get(`/v1/school/reading-tasks/completions/${completionId}`); // ========== 旧 API(保留向后兼容,但不再使用) ========== 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(`/v1/school/tasks/${id}`); export const createSchoolTask = (data: CreateSchoolTaskDto) => http.post('/v1/school/tasks', data); export const updateSchoolTask = (id: number, data: UpdateSchoolTaskDto) => http.put(`/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(`/v1/school/tasks/${taskId}/completions`); export const getSchoolClasses = () => http.get('/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('/v1/school/reports/overview'); export const getTeacherReports = () => http.get('/v1/school/reports/teachers'); export const getCourseReports = () => http.get('/v1/school/reports/courses'); export const getStudentReports = () => http.get('/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(`/v1/school/parents/${id}`); export const createParent = (data: CreateParentDto) => { const { loginAccount, ...rest } = data; return http.post('/v1/school/parents', { ...rest, username: loginAccount, }); }; export const updateParent = (id: number, data: UpdateParentDto) => http.put(`/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 => { const list = await http.get(`/v1/school/parents/${parentId}/children`); return Array.isArray(list) ? list : []; }; export const addChildToParent = (parentId: number, data: AddChildDto) => http.post(`/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}`);