kindergarten_java/reading-platform-frontend/src/api/parent.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

284 lines
7.7 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 ChildInfo {
id: number;
name: string;
gender?: string;
birthDate?: string;
relationship: string;
class: {
id: number;
name: string;
grade: string;
};
readingCount: number;
lessonCount: number;
}
export interface ChildProfile extends ChildInfo {
stats: {
lessonRecords: number;
growthRecords: number;
taskCompletions: number;
};
}
export interface LessonRecord {
id: number;
lesson: {
id: number;
startDatetime: string;
endDatetime?: string;
actualDuration?: number;
course: {
id: number;
name: string;
pictureBookName?: string;
};
};
focus?: number;
participation?: number;
interest?: number;
understanding?: number;
notes?: string;
createdAt: string;
}
// 任务完成状态
export type TaskCompletionStatus = 'PENDING' | 'SUBMITTED' | 'REVIEWED';
// 教师评价结果
export type FeedbackResult = 'EXCELLENT' | 'PASSED' | 'NEEDS_WORK';
// 教师评价
export interface TeacherFeedback {
id: number;
result: FeedbackResult;
resultText?: string;
rating?: number;
comment?: string;
createdAt: string;
teacherName?: string;
}
// 任务完成记录(新设计)
export interface TaskCompletion {
id: number;
taskId: number;
studentId: number;
status: TaskCompletionStatus;
statusText?: string;
photos?: string[];
videoUrl?: string;
audioUrl?: string;
content?: string;
submittedAt?: string;
reviewedAt?: string;
createdAt: string;
feedback?: TeacherFeedback;
}
// 任务完成提交请求
export interface TaskSubmitRequest {
studentId: number;
photos?: string[];
videoUrl?: string;
audioUrl?: string;
content?: string;
}
// 带完成信息的任务(兼容旧接口)
export interface TaskWithCompletion {
id: number;
studentId?: number; // 学生ID多孩子聚合时用于标识任务归属
status: TaskCompletionStatus;
completedAt?: string;
feedback?: string;
parentFeedback?: string;
submittedAt?: string;
reviewedAt?: string;
photos?: string[];
videoUrl?: string;
audioUrl?: string;
content?: string;
teacherFeedback?: TeacherFeedback;
task: {
id: number;
title: string;
description?: string;
taskType: string;
startDate: string;
endDate: string;
relatedBookName?: string;
course?: {
id: number;
name: string;
};
};
}
export interface GrowthRecord {
id: number;
title: string;
content?: string;
images: string[];
recordDate: string;
recordType: string;
class?: {
id: number;
name: string;
};
createdAt: string;
}
export interface Notification {
id: number;
title: string;
content: string;
notificationType: string;
isRead: boolean;
readAt?: string;
createdAt: string;
}
// ==================== 孩子信息 API ====================
export const getChildren = (): Promise<ChildInfo[]> =>
http.get('/v1/parent/children');
export const getChildProfile = (childId: number): Promise<ChildProfile> =>
http.get(`/v1/parent/children/${childId}`);
// ==================== 阅读记录 API ====================
export const getChildLessons = (
childId: number,
params?: { pageNum?: number; pageSize?: number; page?: number }
): Promise<{ items: LessonRecord[]; total: number; page: number; pageSize: number }> =>
http.get<{ list: LessonRecord[]; total: number; pageNum: number; pageSize: number }>(`/v1/parent/children/${childId}/lessons`, {
params: { pageNum: params?.pageNum ?? params?.page ?? 1, pageSize: params?.pageSize ?? 10 },
}).then(res => ({
items: res.list || [],
total: res.total || 0,
page: res.pageNum || 1,
pageSize: res.pageSize || 10,
}));
// ==================== 任务 API ====================
/** 获取我的任务列表(聚合多孩子任务,无 childId 时使用) */
export const getMyTasks = (
params?: { pageNum?: number; pageSize?: number; status?: string }
): Promise<{ items: TaskWithCompletion[]; total: number; page: number; pageSize: number }> =>
http.get<{ list: TaskWithCompletion[]; total: number; pageNum: number; pageSize: number }>('/v1/parent/tasks', { params }).then(res => ({
items: res.list || [],
total: res.total || 0,
page: res.pageNum || 1,
pageSize: res.pageSize || 10,
}));
/** 获取指定孩子的任务列表 */
export const getChildTasks = (
childId: number,
params?: { pageNum?: number; pageSize?: number; status?: string }
): Promise<{ items: TaskWithCompletion[]; total: number; page: number; pageSize: number }> =>
http.get<{ list: TaskWithCompletion[]; total: number; pageNum: number; pageSize: number }>(`/v1/parent/tasks/student/${childId}`, { params }).then(res => ({
items: res.list || [],
total: res.total || 0,
page: res.pageNum || 1,
pageSize: res.pageSize || 10,
}));
// 提交任务完成(新版)
export const submitTaskCompletion = (
taskId: number,
data: TaskSubmitRequest
): Promise<TaskCompletion> =>
http.post(`/v1/parent/tasks/${taskId}/submit`, data) as any;
// 修改任务提交
export const updateTaskCompletion = (
taskId: number,
data: TaskSubmitRequest
): Promise<TaskCompletion> =>
http.put(`/v1/parent/tasks/${taskId}/submit`, data) as any;
// 获取提交详情
export const getCompletionDetail = (
completionId: number
): Promise<TaskCompletion> =>
http.get(`/v1/parent/tasks/completions/${completionId}`) as any;
// 获取教师评价
export const getCompletionFeedback = (
completionId: number
): Promise<TeacherFeedback> =>
http.get(`/v1/parent/tasks/completions/${completionId}/feedback`) as any;
// 兼容旧接口(保留向后兼容)
export const submitTaskFeedback = (
childId: number,
taskId: number,
feedback: string
): Promise<any> =>
http.post(`/v1/parent/tasks/${taskId}/complete`, {
studentId: childId,
content: feedback,
});
// ==================== 成长档案 API ====================
export const getChildGrowthRecords = (
childId: number,
params?: { pageNum?: number; pageSize?: number }
): Promise<{ items: GrowthRecord[]; total: number; page: number; pageSize: number }> =>
http.get<{ list: GrowthRecord[]; total: number; pageNum: number; pageSize: number }>(`/v1/parent/growth-records/student/${childId}`, { params })
.then(res => ({
items: res.list || [],
total: res.total || 0,
page: res.pageNum || 1,
pageSize: res.pageSize || 10,
}));
// ==================== 通知 API ====================
export const getNotifications = (
params?: { pageNum?: number; pageSize?: number; isRead?: boolean; notificationType?: string }
): Promise<{
items: Notification[];
total: number;
unreadCount: number;
page: number;
pageSize: number;
}> => {
const queryParams: Record<string, any> = {
pageNum: params?.pageNum ?? 1,
pageSize: params?.pageSize ?? 10,
};
if (params?.isRead !== undefined) {
queryParams.isRead = params.isRead ? 1 : 0;
}
if (params?.notificationType) {
queryParams.notificationType = params.notificationType;
}
return http.get<{ list: Notification[]; total: number; pageNum: number; pageSize: number }>('/v1/parent/notifications', { params: queryParams })
.then(res => ({
items: res.list || [],
total: res.total || 0,
unreadCount: 0,
page: res.pageNum || 1,
pageSize: res.pageSize || 10,
}));
};
export const getUnreadCount = (): Promise<number> =>
http.get<number>('/v1/parent/notifications/unread-count').then(res => res || 0);
export const markNotificationAsRead = (id: number): Promise<any> =>
http.post(`/v1/parent/notifications/${id}/read`);
export const markAllNotificationsAsRead = (): Promise<any> =>
http.post('/v1/parent/notifications/read-all');