diff --git a/reading-platform-frontend/src/api/school.ts b/reading-platform-frontend/src/api/school.ts index ae54440..8e50f8c 100644 --- a/reading-platform-frontend/src/api/school.ts +++ b/reading-platform-frontend/src/api/school.ts @@ -997,12 +997,17 @@ export interface TaskCompletion { id: number; taskId: number; studentId: number; - studentName: string; - className: string; status: 'PENDING' | 'IN_PROGRESS' | 'COMPLETED'; completedAt?: string; + feedback?: string; parentFeedback?: string; rating?: number; + student?: { + id: number; + name: string; + gender?: string; + class?: { id: number; name: string }; + }; } export interface CreateSchoolTaskDto { @@ -1046,8 +1051,27 @@ export const updateSchoolTask = (id: number, data: UpdateSchoolTaskDto) => 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 interface TaskCompletionListResponse { + items: TaskCompletion[]; + total: number; + page: number; + pageSize: number; + stats: { PENDING: number; IN_PROGRESS: number; COMPLETED: number }; +} + +export const getSchoolTaskCompletions = ( + taskId: number, + params?: { page?: number; pageSize?: number; status?: string } +) => + http.get(`/v1/school/tasks/${taskId}/completions`, { + params: { page: params?.page ?? 1, pageSize: params?.pageSize ?? 20, status: params?.status }, + }).then((res: TaskCompletionListResponse) => ({ + items: res.items ?? [], + total: res.total ?? 0, + page: res.page ?? 1, + pageSize: res.pageSize ?? 20, + stats: res.stats ?? { PENDING: 0, IN_PROGRESS: 0, COMPLETED: 0 }, + })); export const getSchoolClasses = () => http.get('/v1/school/classes'); diff --git a/reading-platform-frontend/src/api/teacher.ts b/reading-platform-frontend/src/api/teacher.ts index 2b3e61b..9883ff8 100644 --- a/reading-platform-frontend/src/api/teacher.ts +++ b/reading-platform-frontend/src/api/teacher.ts @@ -706,9 +706,17 @@ export const getTeacherTasks = (params?: { pageNum?: number; pageSize?: number; export const getTeacherTask = (id: number) => http.get(`/v1/teacher/tasks/${id}`) as any; -// 教师端没有这些接口,返回空数据 -export const getTeacherTaskCompletions = (_taskId: number) => - Promise.resolve([]); +// 获取教师任务完成情况 +export const getTeacherTaskCompletions = (taskId: number, params?: { page?: number; pageSize?: number; status?: string }) => + http.get<{ items: TaskCompletion[]; total: number; page: number; pageSize: number }>( + `/v1/teacher/tasks/${taskId}/completions`, + { params: { page: params?.page ?? 1, pageSize: params?.pageSize ?? 20, status: params?.status } } + ).then(res => ({ + items: res.items ?? res.list ?? [], + total: res.total ?? 0, + page: res.page ?? res.pageNum ?? 1, + pageSize: res.pageSize ?? 20, + })); export const createTeacherTask = (data: CreateTeacherTaskDto) => http.post('/v1/teacher/tasks', data) as any; @@ -719,9 +727,9 @@ export const updateTeacherTask = (id: number, data: Partial http.delete(`/v1/teacher/tasks/${id}`) as any; -// 后端没有这些接口 -export const updateTaskCompletion = (_taskId: number, _studentId: number, _data: UpdateTaskCompletionDto) => - Promise.reject(new Error('接口未实现')); +// 更新任务完成状态 +export const updateTaskCompletion = (taskId: number, studentId: number, data: UpdateTaskCompletionDto) => + http.put(`/v1/teacher/tasks/${taskId}/completions/${studentId}`, data) as Promise; export const sendTaskReminder = (_taskId: number) => Promise.reject(new Error('接口未实现')); diff --git a/reading-platform-frontend/src/views/school/tasks/TaskListView.vue b/reading-platform-frontend/src/views/school/tasks/TaskListView.vue index 3a4e4ba..fd6babf 100644 --- a/reading-platform-frontend/src/views/school/tasks/TaskListView.vue +++ b/reading-platform-frontend/src/views/school/tasks/TaskListView.vue @@ -46,35 +46,18 @@
- + 进行中 草稿 已归档 - + 阅读 活动 作业 - +
@@ -107,12 +90,8 @@ @@ -282,6 +245,10 @@ const editTaskId = ref(null); const tasks = ref([]); const classes = ref([]); const completions = ref([]); +const completionTotal = ref(0); +const completionPage = ref(1); +const completionPageSize = ref(10); +const completionFilter = reactive({ status: undefined as string | undefined }); const selectedTask = ref(null); const loadingCompletions = ref(false); @@ -363,7 +330,7 @@ const getCompletionRate = (task: SchoolTask) => { return Math.round((completed / task.completionCount) * 100); }; -const getCompletedCount = (task: SchoolTask) => { +const getCompletedCount = (_task: SchoolTask) => { return completions.value.filter(c => c.status === 'COMPLETED').length; }; @@ -389,7 +356,7 @@ const loadTasks = async () => { loading.value = true; try { const result = await getSchoolTasks({ - page: currentPage.value, + pageNum: currentPage.value, pageSize: pageSize.value, status: filters.status, taskType: filters.taskType, @@ -499,23 +466,22 @@ const handleDelete = async (id: number) => { } }; -const viewCompletionDetail = async (task: SchoolTask) => { - selectedTask.value = task; - completionModalVisible.value = true; +const loadCompletions = async () => { + if (!selectedTask.value) return; loadingCompletions.value = true; - try { - const result = await getSchoolTaskCompletions(task.id, { pageSize: 100 }); - completions.value = result.list; - - // 计算统计 - completionStats.pending = result.list.filter(c => c.status === 'PENDING').length; - completionStats.inProgress = result.list.filter(c => c.status === 'IN_PROGRESS').length; - completionStats.completed = result.list.filter(c => c.status === 'COMPLETED').length; - - // 计算完成率 - const total = result.list.length; - stats.completionRate = total > 0 ? Math.round((completionStats.completed / total) * 100) : 0; + const data = await getSchoolTaskCompletions(selectedTask.value.id, { + page: completionPage.value, + pageSize: completionPageSize.value, + status: completionFilter.status, + }); + completions.value = data.items; + completionTotal.value = data.total; + completionStats.pending = data.stats.PENDING ?? 0; + completionStats.inProgress = data.stats.IN_PROGRESS ?? 0; + completionStats.completed = data.stats.COMPLETED ?? 0; + const totalCount = completionStats.pending + completionStats.inProgress + completionStats.completed; + stats.completionRate = totalCount > 0 ? Math.round((completionStats.completed / totalCount) * 100) : 0; } catch (error: any) { message.error(error.response?.data?.message || '获取完成情况失败'); } finally { @@ -523,6 +489,19 @@ const viewCompletionDetail = async (task: SchoolTask) => { } }; +const viewCompletionDetail = async (task: SchoolTask) => { + selectedTask.value = task; + completionPage.value = 1; + completionFilter.status = undefined; + completionModalVisible.value = true; + loadCompletions(); +}; + +const onCompletionPageChange = (page: number) => { + completionPage.value = page; + loadCompletions(); +}; + const onPageChange = (page: number) => { currentPage.value = page; loadTasks(); @@ -729,9 +708,9 @@ onMounted(() => { } .completion-stats { - margin-bottom: 16px; display: flex; gap: 8px; + margin-bottom: 16px; } .feedback-text { diff --git a/reading-platform-frontend/src/views/teacher/tasks/TaskListView.vue b/reading-platform-frontend/src/views/teacher/tasks/TaskListView.vue index 0243517..6f27a0b 100644 --- a/reading-platform-frontend/src/views/teacher/tasks/TaskListView.vue +++ b/reading-platform-frontend/src/views/teacher/tasks/TaskListView.vue @@ -2,7 +2,9 @@