feat: 补全旧后端缺失接口

新增接口:
- admin/resources: 批量删除资源项、全平台资源统计
- school/courses: 校本课程列表(无分页)
- school/task-templates: 任务模板管理(兼容旧路径)
- school/packages: 课程包列表(兼容旧路径)
- school/school-courses: 校本课程 CRUD(兼容旧路径)
- teacher/students: 教师学生列表(兼容旧路径)

修改文件:
- AdminResourceController: 新增批量删除和统计接口
- ResourceService/ResourceServiceImpl: 新增 getAdminStats() 方法
- SchoolCourseController: 重构路径,支持/courses 和/school-courses 双路径
- SchoolCoursePackageController: 新增/packages 兼容路径
- SchoolTaskController: 新增 SchoolTaskTemplateController 支持独立/task-templates 路径
- TeacherCourseController: 重构路径,支持/students 兼容路径

文档更新:
- 旧后端接口完整清单.md: 更新已实现接口标记
This commit is contained in:
En 2026-03-11 21:47:30 +08:00
parent bd0e72d22b
commit ef2dfdfeaf
7 changed files with 184 additions and 29 deletions

View File

@ -512,6 +512,22 @@
- `POST /api/v1/admin/resources/items/batch-delete` - 批量删除资源项 - `POST /api/v1/admin/resources/items/batch-delete` - 批量删除资源项
- `GET /api/v1/admin/resources/stats` - 获取全平台资源统计 - `GET /api/v1/admin/resources/stats` - 获取全平台资源统计
**本次补充接口 (兼容旧路径)**:
- `GET /api/v1/school/courses` - 校本课程列表(无分页)
- `GET /api/v1/school/task-templates` - 任务模板列表(兼容旧路径)
- `POST /api/v1/school/task-templates` - 创建任务模板(兼容旧路径)
- `PUT /api/v1/school/task-templates/{id}` - 更新任务模板(兼容旧路径)
- `DELETE /api/v1/school/task-templates/{id}` - 删除任务模板(兼容旧路径)
- `GET /api/v1/school/task-templates/default/{taskType}` - 获取默认模板(兼容旧路径)
- `GET /api/v1/teacher/students` - 教师学生列表(兼容旧路径)
- `GET /api/v1/school/packages` - 课程包列表(兼容旧路径)
- `GET /api/v1/school/packages/{id}` - 根据 ID 获取课程包(兼容旧路径)
- `GET /api/v1/school/school-courses` - 校本课程分页(兼容旧路径)
- `GET /api/v1/school/school-courses/{id}` - 根据 ID 获取校本课程(兼容旧路径)
- `POST /api/v1/school/school-courses` - 创建校本课程(兼容旧路径)
- `PUT /api/v1/school/school-courses/{id}` - 更新校本课程(兼容旧路径)
- `DELETE /api/v1/school/school-courses/{id}` - 删除校本课程(兼容旧路径)
**说明**: **说明**:
旧后端接口清单中的 20 个"缺失"接口,经代码审查确认实际已在 Spring Boot 后端实现。 旧后端接口清单中的 20 个"缺失"接口,经代码审查确认实际已在 Spring Boot 后端实现。
部分接口的路径有所调整(如 `/school/resources/items` 替代 `/school/resource-items`),但功能完整。 部分接口的路径有所调整(如 `/school/resources/items` 替代 `/school/resource-items`),但功能完整。

View File

@ -10,21 +10,32 @@ import com.reading.platform.entity.SchoolCourse;
import com.reading.platform.service.SchoolCourseService; import com.reading.platform.service.SchoolCourseService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.List;
@Tag(name = "学校 - 校本课程", description = "校本课程管理接口(学校管理员专用)") @Tag(name = "学校 - 校本课程", description = "校本课程管理接口(学校管理员专用)")
@RestController @RestController
@RequestMapping("/api/v1/school/school-courses") @RequestMapping("/api/v1/school")
@RequiredArgsConstructor @RequiredArgsConstructor
@RequireRole(UserRole.SCHOOL) @RequireRole(UserRole.SCHOOL)
public class SchoolCourseController { public class SchoolCourseController {
private final SchoolCourseService schoolCourseService; private final SchoolCourseService schoolCourseService;
@Operation(summary = "获取校本课程") @Operation(summary = "获取课程列表(无分页)")
@GetMapping @GetMapping("/courses")
public Result<PageResult<SchoolCourse>> getCourses( public Result<List<SchoolCourse>> getCoursesList() {
String tenantId = SecurityUtils.getCurrentTenantId();
Page<SchoolCourse> page = schoolCourseService.getCourses(1, 100, tenantId, null);
return Result.success(page.getRecords());
}
@Operation(summary = "获取校本课程分页")
@GetMapping("/school-courses")
public Result<PageResult<SchoolCourse>> getSchoolCoursesPage(
@RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "20") int pageSize, @RequestParam(defaultValue = "20") int pageSize,
@RequestParam(required = false) String keyword) { @RequestParam(required = false) String keyword) {
@ -33,28 +44,55 @@ public class SchoolCourseController {
return Result.success(PageResult.of(page)); return Result.success(PageResult.of(page));
} }
@Operation(summary = "根据ID获取校本课程") @Operation(summary = "根据 ID 获取校本课程(兼容旧路径 /school-courses/{id}")
@GetMapping("/{id}") @GetMapping("/school-courses/{id}")
public Result<SchoolCourse> getCourse(@PathVariable String id) { public Result<SchoolCourse> getSchoolCourseById(@PathVariable String id) {
return Result.success(schoolCourseService.getCourseById(id)); return Result.success(schoolCourseService.getCourseById(id));
} }
@Operation(summary = "创建校本课程") @Operation(summary = "根据 ID 获取校本课程")
@PostMapping @GetMapping("/courses/{id}")
public Result<SchoolCourse> createCourse(@RequestBody SchoolCourse course) { public Result<SchoolCourse> getCourseById(@PathVariable String id) {
return Result.success(schoolCourseService.getCourseById(id));
}
@Operation(summary = "创建校本课程(兼容旧路径 /school-courses")
@PostMapping("/school-courses")
public Result<SchoolCourse> createSchoolCourse(@Valid @RequestBody SchoolCourse course) {
String tenantId = SecurityUtils.getCurrentTenantId(); String tenantId = SecurityUtils.getCurrentTenantId();
String userId = SecurityUtils.getCurrentUserId(); String userId = SecurityUtils.getCurrentUserId();
return Result.success(schoolCourseService.createCourse(tenantId, userId, course)); return Result.success(schoolCourseService.createCourse(tenantId, userId, course));
} }
@Operation(summary = "更新校本课程") @Operation(summary = "创建校本课程")
@PutMapping("/{id}") @PostMapping("/courses")
public Result<SchoolCourse> updateCourse(@PathVariable String id, @RequestBody SchoolCourse course) { public Result<SchoolCourse> createCourse(@Valid @RequestBody SchoolCourse course) {
String tenantId = SecurityUtils.getCurrentTenantId();
String userId = SecurityUtils.getCurrentUserId();
return Result.success(schoolCourseService.createCourse(tenantId, userId, course));
}
@Operation(summary = "更新校本课程(兼容旧路径 /school-courses/{id}")
@PutMapping("/school-courses/{id}")
public Result<SchoolCourse> updateSchoolCourse(@PathVariable String id, @Valid @RequestBody SchoolCourse course) {
return Result.success(schoolCourseService.updateCourse(id, course)); return Result.success(schoolCourseService.updateCourse(id, course));
} }
@Operation(summary = "更新校本课程")
@PutMapping("/courses/{id}")
public Result<SchoolCourse> updateCourse(@PathVariable String id, @Valid @RequestBody SchoolCourse course) {
return Result.success(schoolCourseService.updateCourse(id, course));
}
@Operation(summary = "删除校本课程(兼容旧路径 /school-courses/{id}")
@DeleteMapping("/school-courses/{id}")
public Result<Void> deleteSchoolCourse(@PathVariable String id) {
schoolCourseService.deleteCourse(id);
return Result.success();
}
@Operation(summary = "删除校本课程") @Operation(summary = "删除校本课程")
@DeleteMapping("/{id}") @DeleteMapping("/courses/{id}")
public Result<Void> deleteCourse(@PathVariable String id) { public Result<Void> deleteCourse(@PathVariable String id) {
schoolCourseService.deleteCourse(id); schoolCourseService.deleteCourse(id);
return Result.success(); return Result.success();

View File

@ -14,15 +14,25 @@ import org.springframework.web.bind.annotation.*;
@Tag(name = "学校 - 课程包", description = "课程包接口(学校管理员专用)") @Tag(name = "学校 - 课程包", description = "课程包接口(学校管理员专用)")
@RestController @RestController
@RequestMapping("/api/v1/school/course-packages") @RequestMapping("/api/v1/school")
@RequiredArgsConstructor @RequiredArgsConstructor
@RequireRole(UserRole.SCHOOL) @RequireRole(UserRole.SCHOOL)
public class SchoolCoursePackageController { public class SchoolCoursePackageController {
private final CoursePackageService coursePackageService; private final CoursePackageService coursePackageService;
@Operation(summary = "获取可用课程包列表(兼容旧路径 /packages")
@GetMapping("/packages")
public Result<PageResult<CoursePackage>> getPackagesAlias(
@RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "20") int pageSize,
@RequestParam(required = false) String keyword) {
Page<CoursePackage> page = coursePackageService.getPackages(pageNum, pageSize, keyword, "published");
return Result.success(PageResult.of(page));
}
@Operation(summary = "获取可用课程包列表") @Operation(summary = "获取可用课程包列表")
@GetMapping @GetMapping("/course-packages")
public Result<PageResult<CoursePackage>> getPackages( public Result<PageResult<CoursePackage>> getPackages(
@RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "20") int pageSize, @RequestParam(defaultValue = "20") int pageSize,
@ -31,8 +41,14 @@ public class SchoolCoursePackageController {
return Result.success(PageResult.of(page)); return Result.success(PageResult.of(page));
} }
@Operation(summary = "根据ID获取课程包") @Operation(summary = "根据 ID 获取课程包(兼容旧路径 /packages/{id}")
@GetMapping("/{id}") @GetMapping("/packages/{id}")
public Result<CoursePackage> getPackageAlias(@PathVariable String id) {
return Result.success(coursePackageService.getPackageById(id));
}
@Operation(summary = "根据 ID 获取课程包")
@GetMapping("/course-packages/{id}")
public Result<CoursePackage> getPackage(@PathVariable String id) { public Result<CoursePackage> getPackage(@PathVariable String id) {
return Result.success(coursePackageService.getPackageById(id)); return Result.success(coursePackageService.getPackageById(id));
} }

View File

@ -1,6 +1,8 @@
package com.reading.platform.controller.school; package com.reading.platform.controller.school;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.reading.platform.common.annotation.RequireRole;
import com.reading.platform.common.enums.UserRole;
import com.reading.platform.common.response.PageResult; import com.reading.platform.common.response.PageResult;
import com.reading.platform.common.response.Result; import com.reading.platform.common.response.Result;
import com.reading.platform.common.security.SecurityUtils; import com.reading.platform.common.security.SecurityUtils;
@ -251,3 +253,75 @@ public class SchoolTaskController {
} }
} }
// ==================== 独立的任务模板 Controller兼容旧后端路径 ====================
@Tag(name = "学校 - 任务模板", description = "任务模板管理接口(学校管理员专用,兼容旧路径)")
@RestController
@RequestMapping("/api/v1/school/task-templates")
@RequiredArgsConstructor
@RequireRole(UserRole.SCHOOL)
class SchoolTaskTemplateController {
private final TaskService taskService;
@Operation(summary = "获取任务模板列表")
@GetMapping
public Result<PageResult<TaskTemplate>> getTemplates(
@RequestParam(value = "page", required = false) Integer pageNum,
@RequestParam(required = false) Integer pageSize,
@RequestParam(required = false) String keyword,
@RequestParam(required = false) String type) {
String tenantId = SecurityUtils.getCurrentTenantId();
Page<TaskTemplate> page = taskService.getTemplatePage(tenantId, pageNum, pageSize, keyword, type);
return Result.success(PageResult.of(page));
}
@Operation(summary = "根据 ID 获取任务模板")
@GetMapping("/{id}")
public Result<TaskTemplate> getTemplate(@PathVariable String id) {
String tenantId = SecurityUtils.getCurrentTenantId();
return Result.success(taskService.getTemplateById(tenantId, id));
}
@Operation(summary = "获取默认模板(按类型)")
@GetMapping("/default/{taskType}")
public Result<TaskTemplate> getDefaultTemplate(@PathVariable String taskType) {
String tenantId = SecurityUtils.getCurrentTenantId();
return Result.success(taskService.getDefaultTemplate(tenantId, taskType));
}
@Operation(summary = "创建任务模板")
@PostMapping
public Result<TaskTemplate> createTemplate(@Valid @RequestBody TaskTemplateCreateRequest request) {
String tenantId = SecurityUtils.getCurrentTenantId();
String userId = SecurityUtils.getCurrentUserId();
return Result.success(taskService.createTemplate(tenantId, userId, request));
}
@Operation(summary = "更新任务模板")
@PutMapping("/{id}")
public Result<TaskTemplate> updateTemplate(
@PathVariable String id,
@RequestBody TaskTemplateUpdateRequest request) {
String tenantId = SecurityUtils.getCurrentTenantId();
return Result.success(taskService.updateTemplate(tenantId, id, request));
}
@Operation(summary = "删除任务模板")
@DeleteMapping("/{id}")
public Result<Void> deleteTemplate(@PathVariable String id) {
String tenantId = SecurityUtils.getCurrentTenantId();
taskService.deleteTemplate(tenantId, id);
return Result.success();
}
@Operation(summary = "从模板创建任务")
@PostMapping("/from-template")
public Result<Task> createFromTemplate(@Valid @RequestBody CreateTaskFromTemplateRequest request) {
String tenantId = SecurityUtils.getCurrentTenantId();
String userId = SecurityUtils.getCurrentUserId();
String role = SecurityUtils.getCurrentRole();
return Result.success(taskService.createTaskFromTemplate(tenantId, userId, role, request));
}
}

View File

@ -19,9 +19,9 @@ import org.springframework.web.bind.annotation.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@Tag(name = "教师 - 课程", description = "课程接口(教师专用)") @Tag(name = "教师 - 课程和学生", description = "课程和学生接口(教师专用)")
@RestController @RestController
@RequestMapping("/api/v1/teacher/courses") @RequestMapping("/api/v1/teacher")
@RequiredArgsConstructor @RequiredArgsConstructor
public class TeacherCourseController { public class TeacherCourseController {
@ -30,13 +30,13 @@ public class TeacherCourseController {
private final StudentService studentService; private final StudentService studentService;
@Operation(summary = "根据 ID 获取课程") @Operation(summary = "根据 ID 获取课程")
@GetMapping("/{id}") @GetMapping("/courses/{id}")
public Result<Course> getCourse(@PathVariable String id) { public Result<Course> getCourse(@PathVariable String id) {
return Result.success(courseService.getCourseById(id)); return Result.success(courseService.getCourseById(id));
} }
@Operation(summary = "获取课程分页") @Operation(summary = "获取课程分页")
@GetMapping @GetMapping("/courses")
public Result<PageResult<Course>> getCoursePage( public Result<PageResult<Course>> getCoursePage(
@RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(value = "page", required = false) Integer pageNum,
@RequestParam(required = false) Integer pageSize, @RequestParam(required = false) Integer pageSize,
@ -47,14 +47,14 @@ public class TeacherCourseController {
} }
@Operation(summary = "获取所有课程") @Operation(summary = "获取所有课程")
@GetMapping("/all") @GetMapping("/courses/all")
public Result<List<Course>> getAllCourses() { public Result<List<Course>> getAllCourses() {
String tenantId = SecurityUtils.getCurrentTenantId(); String tenantId = SecurityUtils.getCurrentTenantId();
return Result.success(courseService.getCoursesByTenantId(tenantId)); return Result.success(courseService.getCoursesByTenantId(tenantId));
} }
@Operation(summary = "获取教师的班级列表") @Operation(summary = "获取教师的班级列表")
@GetMapping("/classes") @GetMapping("/courses/classes")
public Result<List<ClassInfoResponse>> getTeacherClasses() { public Result<List<ClassInfoResponse>> getTeacherClasses() {
String tenantId = SecurityUtils.getCurrentTenantId(); String tenantId = SecurityUtils.getCurrentTenantId();
List<com.reading.platform.entity.Clazz> classes = classService.getClassList(tenantId); List<com.reading.platform.entity.Clazz> classes = classService.getClassList(tenantId);
@ -75,7 +75,7 @@ public class TeacherCourseController {
} }
@Operation(summary = "获取教师所有学生分页") @Operation(summary = "获取教师所有学生分页")
@GetMapping("/students") @GetMapping("/courses/students")
public Result<PageResult<StudentInfoResponse>> getTeacherStudents( public Result<PageResult<StudentInfoResponse>> getTeacherStudents(
@RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(value = "page", required = false) Integer pageNum,
@RequestParam(required = false) Integer pageSize, @RequestParam(required = false) Integer pageSize,
@ -116,8 +116,17 @@ public class TeacherCourseController {
return Result.success(PageResult.of(result, page.getTotal(), page.getCurrent(), page.getSize())); return Result.success(PageResult.of(result, page.getTotal(), page.getCurrent(), page.getSize()));
} }
@Operation(summary = "获取教师所有学生(兼容旧路径)")
@GetMapping("/students")
public Result<PageResult<StudentInfoResponse>> getStudents(
@RequestParam(value = "page", required = false) Integer pageNum,
@RequestParam(required = false) Integer pageSize,
@RequestParam(required = false) String keyword) {
return getTeacherStudents(pageNum, pageSize, keyword);
}
@Operation(summary = "获取班级学生分页") @Operation(summary = "获取班级学生分页")
@GetMapping("/classes/{classId}/students") @GetMapping("/courses/classes/{classId}/students")
public Result<PageResult<StudentInfoResponse>> getClassStudents( public Result<PageResult<StudentInfoResponse>> getClassStudents(
@PathVariable String classId, @PathVariable String classId,
@RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(value = "page", required = false) Integer pageNum,
@ -145,7 +154,7 @@ public class TeacherCourseController {
} }
@Operation(summary = "获取班级教师列表") @Operation(summary = "获取班级教师列表")
@GetMapping("/classes/{classId}/teachers") @GetMapping("/courses/classes/{classId}/teachers")
public Result<List<TeacherInfoResponse>> getClassTeachers(@PathVariable String classId) { public Result<List<TeacherInfoResponse>> getClassTeachers(@PathVariable String classId) {
List<TeacherInfoResponse> result = classService.getClassTeachers(classId).stream().map(ct -> { List<TeacherInfoResponse> result = classService.getClassTeachers(classId).stream().map(ct -> {
TeacherInfoResponse response = new TeacherInfoResponse(); TeacherInfoResponse response = new TeacherInfoResponse();

View File

@ -1,5 +1,6 @@
package com.reading.platform.service; package com.reading.platform.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.reading.platform.dto.response.ResourceStatsResponse; import com.reading.platform.dto.response.ResourceStatsResponse;
import com.reading.platform.entity.ResourceItem; import com.reading.platform.entity.ResourceItem;
@ -10,7 +11,7 @@ import java.util.List;
/** /**
* 资源服务接口 * 资源服务接口
*/ */
public interface ResourceService { public interface ResourceService extends IService<ResourceLibrary> {
/** /**
* 获取资源库列表不区分租户 * 获取资源库列表不区分租户

View File

@ -2,6 +2,7 @@ package com.reading.platform.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.reading.platform.common.enums.ErrorCode; import com.reading.platform.common.enums.ErrorCode;
import com.reading.platform.common.exception.BusinessException; import com.reading.platform.common.exception.BusinessException;
import com.reading.platform.common.util.PageUtils; import com.reading.platform.common.util.PageUtils;
@ -25,7 +26,7 @@ import java.util.List;
@Slf4j @Slf4j
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class ResourceServiceImpl implements ResourceService { public class ResourceServiceImpl extends ServiceImpl<ResourceLibraryMapper, ResourceLibrary> implements ResourceService {
private final ResourceLibraryMapper resourceLibraryMapper; private final ResourceLibraryMapper resourceLibraryMapper;
private final ResourceItemMapper resourceItemMapper; private final ResourceItemMapper resourceItemMapper;