- 家长端阅读任务:从 task_target 获取任务(学生+班级),支持家长关联孩子查看 - 家长端提交任务:修复照片上传,使用 uploadFile(file, poster) 符合 API 规范 - 教师端任务列表:TaskResponse 新增 targetCount、completionCount,填充目标人数与完成人数 - 数据库迁移:V45 添加 task_completion.photos,V46 添加 submitted_at、reviewed_at - 其他:班级学生、家长孩子、学校班级统计等修复 Made-with: Cursor
284 lines
7.7 KiB
TypeScript
284 lines
7.7 KiB
TypeScript
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');
|