kindergarten_java/reading-platform-frontend/src/api/parent.ts
Claude Opus 4.6 f62aa18e72 feat: 阅读任务模块重写(Phase 1-4)
## 主要变更

### 后端改造 (Phase 1)
- 新增 task_feedback 表存储教师评价
- task 表添加 related_book_name 字段
- task_completion 表添加 video_url, audio_url 字段
- 新增 TaskFeedback 实体和服务层
- 扩展 TaskService 支持完成情况查询和评价功能
- 学校端 API 改为只读模式 (/v1/school/reading-tasks)

### 教师端前端 (Phase 2)
- 创建任务弹窗添加关联绘本字段
- 完成情况弹窗支持新状态值 (PENDING/SUBMITTED/REVIEWED)
- 新增评价弹窗组件(评价结果、评分、评语)
- 显示提交内容预览(照片、视频、音频、文字)

### 家长端前端 (Phase 3)
- 提交功能改造支持照片上传(最多9张)
- 支持视频/音频链接输入
- 阅读心得文字输入
- 新增查看教师评价功能
- 状态驱动操作(待提交/已提交/已评价)

### 学校端前端 (Phase 4)
- 完全重写为只读模式
- 移除创建/编辑/删除功能
- 多维度筛选(关键字、类型、状态、日期、排序)
- 统计卡片(任务数、进行中、已提交、已评价)
- 任务详情弹窗
- 完成情况列表弹窗
- 提交详情弹窗

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

254 lines
6.4 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;
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 }
): Promise<{ items: LessonRecord[]; total: number; page: number; pageSize: number }> =>
http.get(`/v1/parent/children/${childId}/lessons`, { params });
// ==================== 任务 API ====================
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;
}> =>
http.get<{ list: Notification[]; total: number; pageNum: number; pageSize: number }>('/v1/parent/notifications', { params })
.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');