diff --git a/reading-platform-frontend/src/api/school.ts b/reading-platform-frontend/src/api/school.ts index 19ac47b..04bc856 100644 --- a/reading-platform-frontend/src/api/school.ts +++ b/reading-platform-frontend/src/api/school.ts @@ -1170,11 +1170,22 @@ export interface SchoolTaskQueryParams { // ========== 新 API:只读接口 ========== +/** 与后端 TaskResponse 对齐:JSON 中 taskType/endDate(兼容历史 type/dueDate) */ +function normalizeSchoolTask(raw: any): SchoolTask { + if (!raw) return raw; + return { + ...raw, + taskType: (raw.taskType ?? raw.type) as SchoolTask['taskType'], + endDate: (raw.endDate ?? raw.dueDate ?? '') as string, + startDate: (raw.startDate ?? '') as string, + }; +} + // 获取学校端任务列表(只读,多维度筛选) export const getReadingTaskList = (params?: SchoolTaskQueryParams) => http.get<{ list: SchoolTask[]; total: number; pageNum: number; pageSize: number; pages: number }>('/v1/school/reading-tasks', { params }) .then(res => ({ - items: res.list || [], + items: (res.list || []).map(normalizeSchoolTask), total: res.total || 0, pageNum: res.pageNum || 1, pageSize: res.pageSize || 10, @@ -1183,7 +1194,7 @@ export const getReadingTaskList = (params?: SchoolTaskQueryParams) => // 获取任务详情(只读) export const getReadingTaskDetail = (taskId: number) => - http.get(`/v1/school/reading-tasks/${taskId}`); + http.get(`/v1/school/reading-tasks/${taskId}`).then(normalizeSchoolTask); // 获取任务完成情况列表 export const getReadingTaskCompletions = (taskId: number, params?: { diff --git a/reading-platform-frontend/src/api/teacher.ts b/reading-platform-frontend/src/api/teacher.ts index 0b4d2a4..dab06ad 100644 --- a/reading-platform-frontend/src/api/teacher.ts +++ b/reading-platform-frontend/src/api/teacher.ts @@ -761,18 +761,38 @@ export interface UpdateTaskCompletionDto { feedback?: string; } +/** 与后端 TaskResponse 对齐:taskType/endDate(兼容 type/dueDate) */ +function normalizeTeacherTask(raw: any): TeacherTask { + if (!raw) return raw; + return { + ...raw, + taskType: (raw.taskType ?? raw.type) as TeacherTask['taskType'], + endDate: (raw.endDate ?? raw.dueDate ?? '') as string, + startDate: (raw.startDate ?? '') as string, + }; +} + // 获取教师任务列表 -export const getTeacherTasks = (params?: { pageNum?: number; pageSize?: number; keyword?: string; type?: string; status?: string }) => +export const getTeacherTasks = (params?: { + pageNum?: number; + pageSize?: number; + keyword?: string; + type?: string; + taskType?: string; + status?: string; + startDate?: string; + endDate?: string; +}) => http.get<{ list: any[]; total: number; pageNum: number; pageSize: number }>('/v1/teacher/tasks', { params }) .then(res => ({ - items: res.list || [], + items: (res.list || []).map(normalizeTeacherTask), total: res.total || 0, page: res.pageNum || 1, pageSize: res.pageSize || 10, })); export const getTeacherTask = (id: number) => - http.get(`/v1/teacher/tasks/${id}`) as any; + http.get(`/v1/teacher/tasks/${id}`).then(normalizeTeacherTask) as Promise; // 获取任务完成情况列表(新版,支持分页和状态筛选) export const getTeacherTaskCompletions = (taskId: number, params?: { diff --git a/reading-platform-frontend/src/views/school/tasks/TaskListView.vue b/reading-platform-frontend/src/views/school/tasks/TaskListView.vue index 849e99e..8be26e9 100644 --- a/reading-platform-frontend/src/views/school/tasks/TaskListView.vue +++ b/reading-platform-frontend/src/views/school/tasks/TaskListView.vue @@ -132,7 +132,7 @@ - {{ formatDate(task.startDate) }} - {{ formatDate(task.endDate) }} + {{ formatTaskRange(task) }} {{ task.targetCount || 0 }} 个目标 @@ -581,7 +581,24 @@ const feedbackResultTexts: Record = { const getFeedbackResultColor = (result: string) => feedbackResultColors[result] || 'default'; const getFeedbackResultText = (result: string) => feedbackResultTexts[result] || result; -const formatDate = (date?: string) => date ? dayjs(date).format('YYYY-MM-DD') : '-'; +const formatDate = (date?: string | number[] | null) => { + if (date == null || date === '') return '-'; + if (Array.isArray(date) && date.length >= 3) { + const [y, m, d] = date; + return dayjs(`${y}-${String(m).padStart(2, '0')}-${String(d).padStart(2, '0')}`).format('YYYY-MM-DD'); + } + return dayjs(date as string).format('YYYY-MM-DD'); +}; + +/** 列表展示:与后端 startDate/endDate 对齐,避免仅一端有值时出现「日期 --」 */ +const formatTaskRange = (task: SchoolTask) => { + const s = formatDate(task.startDate as any); + const e = formatDate((task as any).endDate ?? (task as any).dueDate); + if (e === '-') return s; + if (s === '-') return e; + return `${s} 至 ${e}`; +}; + const formatDateTime = (date?: string) => date ? dayjs(date).format('YYYY-MM-DD HH:mm') : '-'; // 模拟任务统计数据(实际应该从后端获取) diff --git a/reading-platform-frontend/src/views/teacher/tasks/TaskListView.vue b/reading-platform-frontend/src/views/teacher/tasks/TaskListView.vue index 20ea8a1..111538a 100644 --- a/reading-platform-frontend/src/views/teacher/tasks/TaskListView.vue +++ b/reading-platform-frontend/src/views/teacher/tasks/TaskListView.vue @@ -62,6 +62,13 @@ + @@ -84,7 +91,7 @@ - {{ formatDate(task.startDate) }} - {{ formatDate(task.endDate) }} + {{ formatTaskRange(task) }} {{ task.targetCount || 0 }} 个目标 @@ -439,6 +446,14 @@ const filters = reactive({ keyword: undefined as string | undefined, }); +/** 列表筛选:任务时间范围(与 createForm.dateRange 区分,勿混用) */ +const dateRange = ref<[Dayjs, Dayjs] | null>(null); + +const onDateRangeChange = () => { + currentPage.value = 1; + loadTasks(); +}; + // 统计数据 const stats = computed(() => { const all = tasks.value; @@ -521,7 +536,22 @@ const getTypeText = (type: string) => typeMap[type]?.text || type; const getTypeColor = (type: string) => typeMap[type]?.color || 'default'; const getStatusText = (status: string) => statusMap[status]?.text || status; const getStatusColor = (status: string) => statusMap[status]?.color || 'default'; -const formatDate = (date?: string) => date ? dayjs(date).format('YYYY-MM-DD') : '-'; +const formatDate = (date?: string | number[] | null) => { + if (date == null || date === '') return '-'; + if (Array.isArray(date) && date.length >= 3) { + const [y, m, d] = date; + return dayjs(`${y}-${String(m).padStart(2, '0')}-${String(d).padStart(2, '0')}`).format('YYYY-MM-DD'); + } + return dayjs(date as string).format('YYYY-MM-DD'); +}; + +const formatTaskRange = (task: TeacherTask) => { + const s = formatDate(task.startDate as any); + const e = formatDate((task as any).endDate ?? (task as any).dueDate); + if (e === '-') return s; + if (s === '-') return e; + return `${s} 至 ${e}`; +}; const getCompletionRate = (task: TeacherTask) => { if (!task.completionCount || !task.targetCount) return 0; @@ -546,11 +576,16 @@ const filterCourseOption = (input: string, option: any) => { const loadTasks = async () => { loading.value = true; try { - const data = await getTeacherTasks({ + const params: Parameters[0] = { pageNum: currentPage.value, pageSize: pageSize.value, ...filters, - }); + }; + if (dateRange.value?.[0] && dateRange.value?.[1]) { + params.startDate = dateRange.value[0].format('YYYY-MM-DD'); + params.endDate = dateRange.value[1].format('YYYY-MM-DD'); + } + const data = await getTeacherTasks(params); tasks.value = data.items || []; total.value = data.total || 0; } catch (error: any) { diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherTaskController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherTaskController.java index 25ef0aa..35be491 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherTaskController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherTaskController.java @@ -69,11 +69,13 @@ public class TeacherTaskController { @RequestParam(required = false) String keyword, @RequestParam(required = false) String type, @RequestParam(required = false) String taskType, - @RequestParam(required = false) String status) { + @RequestParam(required = false) String status, + @RequestParam(required = false) String startDate, + @RequestParam(required = false) String endDate) { Long tenantId = SecurityUtils.getCurrentTenantId(); Long teacherId = SecurityUtils.getCurrentUserId(); String typeFilter = (type != null && !type.isEmpty()) ? type : taskType; - Page page = taskService.getTaskPage(tenantId, pageNum, pageSize, keyword, typeFilter, status, teacherId); + Page page = taskService.getTaskPage(tenantId, pageNum, pageSize, keyword, typeFilter, status, teacherId, startDate, endDate); List voList = taskMapper.toVO(page.getRecords()); for (int i = 0; i < voList.size(); i++) { taskService.enrichTaskResponseWithStats(voList.get(i), page.getRecords().get(i).getId()); diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/TaskResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TaskResponse.java index e5c878d..0055276 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/dto/response/TaskResponse.java +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TaskResponse.java @@ -1,5 +1,7 @@ package com.reading.platform.dto.response; +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Builder; import lombok.Data; @@ -29,6 +31,8 @@ public class TaskResponse { private String description; @Schema(description = "任务类型") + @JsonProperty("taskType") + @JsonAlias({"type"}) private String type; @Schema(description = "关联绘本名称") @@ -47,6 +51,8 @@ public class TaskResponse { private LocalDate startDate; @Schema(description = "截止日期") + @JsonProperty("endDate") + @JsonAlias({"dueDate"}) private LocalDate dueDate; @Schema(description = "状态") diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/TaskService.java b/reading-platform-java/src/main/java/com/reading/platform/service/TaskService.java index d39ef44..917fc72 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/TaskService.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/TaskService.java @@ -35,6 +35,11 @@ public interface TaskService extends com.baomidou.mybatisplus.extension.service. */ Page getTaskPage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String type, String status, Long creatorId); + /** + * 分页查询任务(支持按创建人、任务时间范围筛选;与学校端时间交集逻辑一致) + */ + Page getTaskPage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String type, String status, Long creatorId, String startDate, String endDate); + Page getTasksByStudentId(Long studentId, Integer pageNum, Integer pageSize, String status); /** diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/TaskServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/TaskServiceImpl.java index 50e27b4..02e5ff7 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/TaskServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/TaskServiceImpl.java @@ -173,11 +173,16 @@ public class TaskServiceImpl extends ServiceImpl @Override public Page getTaskPage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String type, String status) { - return getTaskPage(tenantId, pageNum, pageSize, keyword, type, status, null); + return getTaskPage(tenantId, pageNum, pageSize, keyword, type, status, null, null, null); } @Override public Page getTaskPage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String type, String status, Long creatorId) { + return getTaskPage(tenantId, pageNum, pageSize, keyword, type, status, creatorId, null, null); + } + + @Override + public Page getTaskPage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String type, String status, Long creatorId, String startDate, String endDate) { Page page = new Page<>(pageNum, pageSize); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); @@ -195,6 +200,33 @@ public class TaskServiceImpl extends ServiceImpl if (StringUtils.hasText(status)) { wrapper.eq(Task::getStatus, status); } + + // 任务时间筛选:与学校端 getSchoolTaskList 一致(任务区间与查询范围有交集) + if (StringUtils.hasText(startDate) && StringUtils.hasText(endDate)) { + try { + LocalDate rangeStart = LocalDate.parse(startDate); + LocalDate rangeEnd = LocalDate.parse(endDate); + wrapper.le(Task::getStartDate, rangeEnd); + wrapper.and(w -> w.ge(Task::getDueDate, rangeStart).or().isNull(Task::getDueDate)); + } catch (Exception e) { + log.warn("解析日期参数失败 startDate={}, endDate={}", startDate, endDate, e); + } + } else if (StringUtils.hasText(startDate)) { + try { + LocalDate rangeStart = LocalDate.parse(startDate); + wrapper.ge(Task::getDueDate, rangeStart); + } catch (Exception e) { + log.warn("解析 startDate 参数失败: {}", startDate, e); + } + } else if (StringUtils.hasText(endDate)) { + try { + LocalDate rangeEnd = LocalDate.parse(endDate); + wrapper.le(Task::getStartDate, rangeEnd); + } catch (Exception e) { + log.warn("解析 endDate 参数失败: {}", endDate, e); + } + } + wrapper.orderByDesc(Task::getCreatedAt); return taskMapper.selectPage(page, wrapper); @@ -758,23 +790,27 @@ public class TaskServiceImpl extends ServiceImpl // 转换为响应对象 // TODO: 使用 TaskMapper 转换 List responses = taskPage.getRecords().stream() - .map(task -> TaskResponse.builder() - .id(task.getId()) - .tenantId(task.getTenantId()) - .title(task.getTitle()) - .description(task.getDescription()) - .type(task.getType()) - .relatedBookName(task.getRelatedBookName()) - .courseId(task.getCourseId()) - .creatorId(task.getCreatorId()) - .creatorRole(task.getCreatorRole()) - .startDate(task.getStartDate()) - .dueDate(task.getDueDate()) - .status(task.getStatus()) - .attachments(task.getAttachments()) - .createdAt(task.getCreatedAt()) - .updatedAt(task.getUpdatedAt()) - .build()) + .map(task -> { + TaskResponse r = TaskResponse.builder() + .id(task.getId()) + .tenantId(task.getTenantId()) + .title(task.getTitle()) + .description(task.getDescription()) + .type(task.getType()) + .relatedBookName(task.getRelatedBookName()) + .courseId(task.getCourseId()) + .creatorId(task.getCreatorId()) + .creatorRole(task.getCreatorRole()) + .startDate(task.getStartDate()) + .dueDate(task.getDueDate()) + .status(task.getStatus()) + .attachments(task.getAttachments()) + .createdAt(task.getCreatedAt()) + .updatedAt(task.getUpdatedAt()) + .build(); + enrichTaskResponseWithStats(r, task.getId()); + return r; + }) .toList(); return PageResult.of(responses, taskPage.getTotal(), taskPage.getCurrent(), taskPage.getSize());