## 主要变更 ### 后端改造 (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>
254 lines
6.4 KiB
TypeScript
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');
|