From 859c71db09b65ef503975a6e36205e77ffea4699 Mon Sep 17 00:00:00 2001 From: tonytech Date: Mon, 2 Mar 2026 15:20:37 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix(backend):=20=E4=BF=AE=E5=A4=8D=E7=A7=9F?= =?UTF-8?q?=E6=88=B7=E5=88=9B=E5=BB=BA=E3=80=81=E6=8E=A5=E5=8F=A3=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E5=92=8C500=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug 1: 创建租户时同步创建学校登录账号(teachers表) - TenantCreateRequest支持loginAccount/contactPerson/studentQuota/teacherQuota字段 - TenantServiceImpl.createTenant()后自动插入Teacher记录,包含BCrypt加密密码 - 返回tempPassword字段供前端展示 Bug 2: 修复多个接口500错误 - 新增POST /auth/logout端点(JWT无状态,直接返回成功) - 新增GET /admin/stats/trend端点(最近6个月统计趋势) - 完善getStats()返回activeTenantCount/publishedCourseCount/monthlyLessons字段 - 新增AdminSettingsController(GET/PUT /admin/settings) - 新增租户操作端点:/status、/reset-password、/quota Bug 3: 统一前后端接口字段名 - Tenant实体用@JsonProperty重命名:code→loginAccount, contactName→contactPerson maxStudents→studentQuota, maxTeachers→teacherQuota, expireAt→expireDate - status字段用UpperCaseSerializer返回大写值(前端期望ACTIVE/SUSPENDED) - TenantCreateRequest/UpdateRequest用@JsonAlias接受前端字段名 - PageResult用@JsonProperty重命名:list→items, pageNum→page, pages→totalPages - 所有分页控制器将pageNum参数改为page(与前端对齐) - 新增TenantService.resetSchoolAccountPassword()方法 Co-Authored-By: Claude Sonnet 4.6 --- .../platform/common/response/PageResult.java | 4 + .../serializer/UpperCaseSerializer.java | 19 +++ .../platform/controller/AuthController.java | 9 +- .../admin/AdminCourseController.java | 4 +- .../admin/AdminSettingsController.java | 44 ++++++ .../admin/AdminTenantController.java | 50 +++++- .../parent/ParentGrowthController.java | 4 +- .../parent/ParentNotificationController.java | 4 +- .../parent/ParentTaskController.java | 4 +- .../school/SchoolClassController.java | 4 +- .../school/SchoolGrowthController.java | 4 +- .../school/SchoolParentController.java | 4 +- .../school/SchoolStudentController.java | 4 +- .../school/SchoolTaskController.java | 4 +- .../school/SchoolTeacherController.java | 4 +- .../teacher/TeacherCourseController.java | 4 +- .../teacher/TeacherGrowthController.java | 4 +- .../teacher/TeacherLessonController.java | 4 +- .../TeacherNotificationController.java | 4 +- .../teacher/TeacherTaskController.java | 4 +- .../dto/request/TenantCreateRequest.java | 19 ++- .../dto/request/TenantUpdateRequest.java | 11 ++ .../platform/dto/response/TenantResponse.java | 16 +- .../com/reading/platform/entity/Tenant.java | 13 ++ .../platform/service/AdminStatsService.java | 148 ++++++++++++++++++ .../platform/service/TenantService.java | 2 + .../service/impl/TenantServiceImpl.java | 51 +++++- 27 files changed, 395 insertions(+), 51 deletions(-) create mode 100644 reading-platform-java/src/main/java/com/reading/platform/common/serializer/UpperCaseSerializer.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminSettingsController.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/service/AdminStatsService.java diff --git a/reading-platform-java/src/main/java/com/reading/platform/common/response/PageResult.java b/reading-platform-java/src/main/java/com/reading/platform/common/response/PageResult.java index 75aca85..d504fd2 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/common/response/PageResult.java +++ b/reading-platform-java/src/main/java/com/reading/platform/common/response/PageResult.java @@ -1,6 +1,7 @@ package com.reading.platform.common.response; import com.baomidou.mybatisplus.core.metadata.IPage; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import java.io.Serializable; @@ -15,10 +16,13 @@ public class PageResult implements Serializable { private static final long serialVersionUID = 1L; + @JsonProperty("items") private List list; private Long total; + @JsonProperty("page") private Long pageNum; private Long pageSize; + @JsonProperty("totalPages") private Long pages; public static PageResult of(List list, Long total, Long pageNum, Long pageSize) { diff --git a/reading-platform-java/src/main/java/com/reading/platform/common/serializer/UpperCaseSerializer.java b/reading-platform-java/src/main/java/com/reading/platform/common/serializer/UpperCaseSerializer.java new file mode 100644 index 0000000..c1b5244 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/common/serializer/UpperCaseSerializer.java @@ -0,0 +1,19 @@ +package com.reading.platform.common.serializer; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; + +import java.io.IOException; + +/** + * Jackson serializer that converts string values to uppercase. + * Used to normalize status fields from DB (lowercase) to JSON output (uppercase). + */ +public class UpperCaseSerializer extends JsonSerializer { + + @Override + public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + gen.writeString(value != null ? value.toUpperCase() : null); + } +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/AuthController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/AuthController.java index 63ef955..72158c9 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/AuthController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/AuthController.java @@ -13,7 +13,7 @@ import org.springframework.web.bind.annotation.*; @Tag(name = "Auth", description = "Authentication APIs") @RestController -@RequestMapping("/api/auth") +@RequestMapping("/api/v1/auth") @RequiredArgsConstructor public class AuthController { @@ -25,6 +25,13 @@ public class AuthController { return Result.success(authService.login(request)); } + @Operation(summary = "User logout") + @PostMapping("/logout") + public Result logout() { + // JWT is stateless - client simply discards the token + return Result.success(); + } + @Operation(summary = "Get current user info") @GetMapping("/me") public Result getCurrentUser() { diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminCourseController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminCourseController.java index 5bfc63b..2e3e1f5 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminCourseController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminCourseController.java @@ -17,7 +17,7 @@ import org.springframework.web.bind.annotation.*; @Tag(name = "Admin - Course", description = "System Course Management APIs for Admin") @RestController -@RequestMapping("/api/admin/courses") +@RequestMapping("/api/v1/admin/courses") @RequiredArgsConstructor @RequireRole(UserRole.ADMIN) public class AdminCourseController { @@ -48,7 +48,7 @@ public class AdminCourseController { @Operation(summary = "Get system course page") @GetMapping public Result> getCoursePage( - @RequestParam(required = false) Integer pageNum, + @RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) String keyword, @RequestParam(required = false) String category) { diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminSettingsController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminSettingsController.java new file mode 100644 index 0000000..55f2ff9 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminSettingsController.java @@ -0,0 +1,44 @@ +package com.reading.platform.controller.admin; + +import com.reading.platform.common.annotation.RequireRole; +import com.reading.platform.common.enums.UserRole; +import com.reading.platform.common.response.Result; +import com.reading.platform.service.SystemSettingService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; + +@Tag(name = "Admin - Settings", description = "Admin System Settings Management") +@RestController +@RequestMapping("/api/v1/admin/settings") +@RequiredArgsConstructor +@RequireRole(UserRole.ADMIN) +public class AdminSettingsController { + + // Use tenantId=0 for global admin settings + private static final Long ADMIN_TENANT_ID = 0L; + + private final SystemSettingService systemSettingService; + + @Operation(summary = "Get admin system settings") + @GetMapping + public Result> getSettings() { + return Result.success(systemSettingService.getSettings(ADMIN_TENANT_ID)); + } + + @Operation(summary = "Update admin system settings") + @PutMapping + public Result updateSettings(@RequestBody Map settings) { + Map stringSettings = new java.util.HashMap<>(); + settings.forEach((k, v) -> { + if (v != null) { + stringSettings.put(k, v.toString()); + } + }); + systemSettingService.updateSettings(ADMIN_TENANT_ID, stringSettings); + return Result.success(); + } +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminTenantController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminTenantController.java index 102ec86..e97e1c0 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminTenantController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/admin/AdminTenantController.java @@ -16,11 +16,13 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; +import java.util.HashMap; import java.util.List; +import java.util.Map; @Tag(name = "Admin - Tenant", description = "Tenant Management APIs for Admin") @RestController -@RequestMapping("/api/admin/tenants") +@RequestMapping("/api/v1/admin/tenants") @RequiredArgsConstructor @RequireRole(UserRole.ADMIN) public class AdminTenantController { @@ -48,10 +50,11 @@ public class AdminTenantController { @Operation(summary = "Get tenant page") @GetMapping public Result> getTenantPage( - @RequestParam(required = false) Integer pageNum, + @RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) String keyword, - @RequestParam(required = false) String status) { + @RequestParam(required = false) String status, + @RequestParam(required = false) String packageType) { Page page = tenantService.getTenantPage(pageNum, pageSize, keyword, status); return Result.success(PageResult.of(page)); } @@ -69,4 +72,45 @@ public class AdminTenantController { return Result.success(tenantService.getAllActiveTenants()); } + @Operation(summary = "Update tenant status") + @PutMapping("/{id}/status") + public Result> updateTenantStatus(@PathVariable Long id, @RequestBody Map body) { + String status = body.get("status"); + // Normalize status to lowercase for DB + String dbStatus = status != null ? status.toLowerCase() : "active"; + TenantUpdateRequest req = new TenantUpdateRequest(); + req.setStatus(dbStatus); + Tenant tenant = tenantService.updateTenant(id, req); + Map result = new HashMap<>(); + result.put("id", tenant.getId()); + result.put("name", tenant.getName()); + result.put("status", tenant.getStatus()); + return Result.success(result); + } + + @Operation(summary = "Reset tenant school account password") + @PostMapping("/{id}/reset-password") + public Result> resetTenantPassword(@PathVariable Long id) { + String tempPassword = tenantService.resetSchoolAccountPassword(id); + Map result = new HashMap<>(); + result.put("tempPassword", tempPassword); + return Result.success(result); + } + + @Operation(summary = "Update tenant quota") + @PutMapping("/{id}/quota") + public Result updateTenantQuota(@PathVariable Long id, @RequestBody Map body) { + TenantUpdateRequest req = new TenantUpdateRequest(); + if (body.get("teacherQuota") != null) { + req.setMaxTeachers(Integer.parseInt(body.get("teacherQuota").toString())); + } + if (body.get("studentQuota") != null) { + req.setMaxStudents(Integer.parseInt(body.get("studentQuota").toString())); + } + if (body.get("packageType") != null) { + req.setPackageType(body.get("packageType").toString()); + } + return Result.success(tenantService.updateTenant(id, req)); + } + } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentGrowthController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentGrowthController.java index 95f6276..2592a71 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentGrowthController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentGrowthController.java @@ -18,7 +18,7 @@ import java.util.List; @Tag(name = "Parent - Growth Record", description = "Growth Record APIs for Parent") @RestController -@RequestMapping("/api/parent/growth-records") +@RequestMapping("/api/v1/parent/growth-records") @RequiredArgsConstructor public class ParentGrowthController { @@ -48,7 +48,7 @@ public class ParentGrowthController { @GetMapping("/student/{studentId}") public Result> getGrowthRecordsByStudent( @PathVariable Long studentId, - @RequestParam(required = false) Integer pageNum, + @RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) String type) { Page page = growthRecordService.getGrowthRecordsByStudentId(studentId, pageNum, pageSize, type); diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentNotificationController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentNotificationController.java index f167c32..7eacace 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentNotificationController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentNotificationController.java @@ -13,7 +13,7 @@ import org.springframework.web.bind.annotation.*; @Tag(name = "Parent - Notification", description = "Notification APIs for Parent") @RestController -@RequestMapping("/api/parent/notifications") +@RequestMapping("/api/v1/parent/notifications") @RequiredArgsConstructor public class ParentNotificationController { @@ -28,7 +28,7 @@ public class ParentNotificationController { @Operation(summary = "Get my notifications") @GetMapping public Result> getMyNotifications( - @RequestParam(required = false) Integer pageNum, + @RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) Integer isRead) { Long userId = SecurityUtils.getCurrentUserId(); diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentTaskController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentTaskController.java index 558528f..5821017 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentTaskController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/parent/ParentTaskController.java @@ -13,7 +13,7 @@ import org.springframework.web.bind.annotation.*; @Tag(name = "Parent - Task", description = "Task APIs for Parent") @RestController -@RequestMapping("/api/parent/tasks") +@RequestMapping("/api/v1/parent/tasks") @RequiredArgsConstructor public class ParentTaskController { @@ -29,7 +29,7 @@ public class ParentTaskController { @GetMapping("/student/{studentId}") public Result> getTasksByStudent( @PathVariable Long studentId, - @RequestParam(required = false) Integer pageNum, + @RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) String status) { Page page = taskService.getTasksByStudentId(studentId, pageNum, pageSize, status); diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolClassController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolClassController.java index 1b79d82..bc398f5 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolClassController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolClassController.java @@ -18,7 +18,7 @@ import java.util.List; @Tag(name = "School - Class", description = "Class Management APIs for School") @RestController -@RequestMapping("/api/school/classes") +@RequestMapping("/api/v1/school/classes") @RequiredArgsConstructor public class SchoolClassController { @@ -46,7 +46,7 @@ public class SchoolClassController { @Operation(summary = "Get class page") @GetMapping public Result> getClassPage( - @RequestParam(required = false) Integer pageNum, + @RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) String keyword, @RequestParam(required = false) String grade, diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolGrowthController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolGrowthController.java index f6595f9..c3b7f9c 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolGrowthController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolGrowthController.java @@ -16,7 +16,7 @@ import org.springframework.web.bind.annotation.*; @Tag(name = "School - Growth Record", description = "Growth Record Management APIs for School") @RestController -@RequestMapping("/api/school/growth-records") +@RequestMapping("/api/v1/school/growth-records") @RequiredArgsConstructor public class SchoolGrowthController { @@ -46,7 +46,7 @@ public class SchoolGrowthController { @Operation(summary = "Get growth record page") @GetMapping public Result> getGrowthRecordPage( - @RequestParam(required = false) Integer pageNum, + @RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) Long studentId, @RequestParam(required = false) String type) { diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolParentController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolParentController.java index 5a54d55..552c899 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolParentController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolParentController.java @@ -16,7 +16,7 @@ import org.springframework.web.bind.annotation.*; @Tag(name = "School - Parent", description = "Parent Management APIs for School") @RestController -@RequestMapping("/api/school/parents") +@RequestMapping("/api/v1/school/parents") @RequiredArgsConstructor public class SchoolParentController { @@ -44,7 +44,7 @@ public class SchoolParentController { @Operation(summary = "Get parent page") @GetMapping public Result> getParentPage( - @RequestParam(required = false) Integer pageNum, + @RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) String keyword, @RequestParam(required = false) String status) { diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolStudentController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolStudentController.java index e0b5c00..b4a33a7 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolStudentController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolStudentController.java @@ -16,7 +16,7 @@ import org.springframework.web.bind.annotation.*; @Tag(name = "School - Student", description = "Student Management APIs for School") @RestController -@RequestMapping("/api/school/students") +@RequestMapping("/api/v1/school/students") @RequiredArgsConstructor public class SchoolStudentController { @@ -44,7 +44,7 @@ public class SchoolStudentController { @Operation(summary = "Get student page") @GetMapping public Result> getStudentPage( - @RequestParam(required = false) Integer pageNum, + @RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) String keyword, @RequestParam(required = false) String grade, diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolTaskController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolTaskController.java index 8836509..13fe2bf 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolTaskController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolTaskController.java @@ -16,7 +16,7 @@ import org.springframework.web.bind.annotation.*; @Tag(name = "School - Task", description = "Task Management APIs for School") @RestController -@RequestMapping("/api/school/tasks") +@RequestMapping("/api/v1/school/tasks") @RequiredArgsConstructor public class SchoolTaskController { @@ -46,7 +46,7 @@ public class SchoolTaskController { @Operation(summary = "Get task page") @GetMapping public Result> getTaskPage( - @RequestParam(required = false) Integer pageNum, + @RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) String keyword, @RequestParam(required = false) String type, diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolTeacherController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolTeacherController.java index 3a49364..0f20407 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolTeacherController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolTeacherController.java @@ -16,7 +16,7 @@ import org.springframework.web.bind.annotation.*; @Tag(name = "School - Teacher", description = "Teacher Management APIs for School") @RestController -@RequestMapping("/api/school/teachers") +@RequestMapping("/api/v1/school/teachers") @RequiredArgsConstructor public class SchoolTeacherController { @@ -44,7 +44,7 @@ public class SchoolTeacherController { @Operation(summary = "Get teacher page") @GetMapping public Result> getTeacherPage( - @RequestParam(required = false) Integer pageNum, + @RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) String keyword, @RequestParam(required = false) String status) { diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherCourseController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherCourseController.java index 1fe4750..ac06236 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherCourseController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherCourseController.java @@ -15,7 +15,7 @@ import java.util.List; @Tag(name = "Teacher - Course", description = "Course APIs for Teacher") @RestController -@RequestMapping("/api/teacher/courses") +@RequestMapping("/api/v1/teacher/courses") @RequiredArgsConstructor public class TeacherCourseController { @@ -30,7 +30,7 @@ public class TeacherCourseController { @Operation(summary = "Get course page") @GetMapping public Result> getCoursePage( - @RequestParam(required = false) Integer pageNum, + @RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) String keyword, @RequestParam(required = false) String category) { diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherGrowthController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherGrowthController.java index edaf222..3ded03d 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherGrowthController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherGrowthController.java @@ -16,7 +16,7 @@ import org.springframework.web.bind.annotation.*; @Tag(name = "Teacher - Growth Record", description = "Growth Record APIs for Teacher") @RestController -@RequestMapping("/api/teacher/growth-records") +@RequestMapping("/api/v1/teacher/growth-records") @RequiredArgsConstructor public class TeacherGrowthController { @@ -45,7 +45,7 @@ public class TeacherGrowthController { @Operation(summary = "Get growth record page") @GetMapping public Result> getGrowthRecordPage( - @RequestParam(required = false) Integer pageNum, + @RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) Long studentId, @RequestParam(required = false) String type) { diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherLessonController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherLessonController.java index 94f4119..33a2cdf 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherLessonController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherLessonController.java @@ -20,7 +20,7 @@ import java.util.List; @Tag(name = "Teacher - Lesson", description = "Lesson APIs for Teacher") @RestController -@RequestMapping("/api/teacher/lessons") +@RequestMapping("/api/v1/teacher/lessons") @RequiredArgsConstructor public class TeacherLessonController { @@ -48,7 +48,7 @@ public class TeacherLessonController { @Operation(summary = "Get my lessons") @GetMapping public Result> getMyLessons( - @RequestParam(required = false) Integer pageNum, + @RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) String status, @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate, diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherNotificationController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherNotificationController.java index fd4020f..e218879 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherNotificationController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherNotificationController.java @@ -13,7 +13,7 @@ import org.springframework.web.bind.annotation.*; @Tag(name = "Teacher - Notification", description = "Notification APIs for Teacher") @RestController -@RequestMapping("/api/teacher/notifications") +@RequestMapping("/api/v1/teacher/notifications") @RequiredArgsConstructor public class TeacherNotificationController { @@ -28,7 +28,7 @@ public class TeacherNotificationController { @Operation(summary = "Get my notifications") @GetMapping public Result> getMyNotifications( - @RequestParam(required = false) Integer pageNum, + @RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) Integer isRead) { Long userId = SecurityUtils.getCurrentUserId(); 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 ffeafc8..ea47e06 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 @@ -16,7 +16,7 @@ import org.springframework.web.bind.annotation.*; @Tag(name = "Teacher - Task", description = "Task APIs for Teacher") @RestController -@RequestMapping("/api/teacher/tasks") +@RequestMapping("/api/v1/teacher/tasks") @RequiredArgsConstructor public class TeacherTaskController { @@ -45,7 +45,7 @@ public class TeacherTaskController { @Operation(summary = "Get task page") @GetMapping public Result> getTaskPage( - @RequestParam(required = false) Integer pageNum, + @RequestParam(value = "page", required = false) Integer pageNum, @RequestParam(required = false) Integer pageSize, @RequestParam(required = false) String keyword, @RequestParam(required = false) String type, diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/request/TenantCreateRequest.java b/reading-platform-java/src/main/java/com/reading/platform/dto/request/TenantCreateRequest.java index b349163..ca091b1 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/dto/request/TenantCreateRequest.java +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/request/TenantCreateRequest.java @@ -1,5 +1,6 @@ package com.reading.platform.dto.request; +import com.fasterxml.jackson.annotation.JsonAlias; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import lombok.Data; @@ -14,10 +15,12 @@ public class TenantCreateRequest { @Schema(description = "Tenant name") private String name; - @NotBlank(message = "Tenant code is required") - @Schema(description = "Tenant code") + @NotBlank(message = "Login account is required") + @JsonAlias("loginAccount") + @Schema(description = "Tenant code / login account") private String code; + @JsonAlias("contactPerson") @Schema(description = "Contact person") private String contactName; @@ -33,13 +36,25 @@ public class TenantCreateRequest { @Schema(description = "Logo URL") private String logoUrl; + @JsonAlias("expireDate") @Schema(description = "Expiration date") private LocalDateTime expireAt; + @JsonAlias("studentQuota") @Schema(description = "Max students") private Integer maxStudents; + @JsonAlias("teacherQuota") @Schema(description = "Max teachers") private Integer maxTeachers; + @Schema(description = "Initial password (default: 123456)") + private String password; + + @Schema(description = "Package type (optional)") + private String packageType; + + @Schema(description = "Start date (optional)") + private String startDate; + } diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/request/TenantUpdateRequest.java b/reading-platform-java/src/main/java/com/reading/platform/dto/request/TenantUpdateRequest.java index 4720ef6..839dc0e 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/dto/request/TenantUpdateRequest.java +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/request/TenantUpdateRequest.java @@ -1,5 +1,6 @@ package com.reading.platform.dto.request; +import com.fasterxml.jackson.annotation.JsonAlias; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -12,6 +13,7 @@ public class TenantUpdateRequest { @Schema(description = "Tenant name") private String name; + @JsonAlias("contactPerson") @Schema(description = "Contact person") private String contactName; @@ -30,13 +32,22 @@ public class TenantUpdateRequest { @Schema(description = "Status") private String status; + @JsonAlias("expireDate") @Schema(description = "Expiration date") private LocalDateTime expireAt; + @JsonAlias("studentQuota") @Schema(description = "Max students") private Integer maxStudents; + @JsonAlias("teacherQuota") @Schema(description = "Max teachers") private Integer maxTeachers; + @Schema(description = "Package type (optional)") + private String packageType; + + @Schema(description = "Start date (optional)") + private String startDate; + } diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/TenantResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TenantResponse.java index 0b8a6aa..c586792 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/dto/response/TenantResponse.java +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/TenantResponse.java @@ -17,11 +17,11 @@ public class TenantResponse { @Schema(description = "Tenant name") private String name; - @Schema(description = "Tenant code") - private String code; + @Schema(description = "Login account (tenant code)") + private String loginAccount; @Schema(description = "Contact person") - private String contactName; + private String contactPerson; @Schema(description = "Contact phone") private String contactPhone; @@ -39,13 +39,13 @@ public class TenantResponse { private String status; @Schema(description = "Expiration date") - private LocalDateTime expireAt; + private LocalDateTime expireDate; - @Schema(description = "Max students") - private Integer maxStudents; + @Schema(description = "Max students / student quota") + private Integer studentQuota; - @Schema(description = "Max teachers") - private Integer maxTeachers; + @Schema(description = "Max teachers / teacher quota") + private Integer teacherQuota; @Schema(description = "Created at") private LocalDateTime createdAt; diff --git a/reading-platform-java/src/main/java/com/reading/platform/entity/Tenant.java b/reading-platform-java/src/main/java/com/reading/platform/entity/Tenant.java index 2667ede..bc8580e 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/entity/Tenant.java +++ b/reading-platform-java/src/main/java/com/reading/platform/entity/Tenant.java @@ -1,6 +1,9 @@ package com.reading.platform.entity; import com.baomidou.mybatisplus.annotation.*; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.reading.platform.common.serializer.UpperCaseSerializer; import lombok.Data; import java.time.LocalDateTime; @@ -17,8 +20,10 @@ public class Tenant { private String name; + @JsonProperty("loginAccount") private String code; + @JsonProperty("contactPerson") private String contactName; private String contactPhone; @@ -29,12 +34,16 @@ public class Tenant { private String logoUrl; + @JsonSerialize(using = UpperCaseSerializer.class) private String status; + @JsonProperty("expireDate") private LocalDateTime expireAt; + @JsonProperty("studentQuota") private Integer maxStudents; + @JsonProperty("teacherQuota") private Integer maxTeachers; @TableField(fill = FieldFill.INSERT) @@ -46,4 +55,8 @@ public class Tenant { @TableLogic private Integer deleted; + // Not persisted - used in create response to return temp password + @TableField(exist = false) + private String tempPassword; + } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/AdminStatsService.java b/reading-platform-java/src/main/java/com/reading/platform/service/AdminStatsService.java new file mode 100644 index 0000000..b3efed3 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/service/AdminStatsService.java @@ -0,0 +1,148 @@ +package com.reading.platform.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.reading.platform.entity.*; +import com.reading.platform.mapper.*; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +@RequiredArgsConstructor +public class AdminStatsService { + + private final TenantMapper tenantMapper; + private final TeacherMapper teacherMapper; + private final StudentMapper studentMapper; + private final CourseMapper courseMapper; + private final LessonMapper lessonMapper; + + public Map getStats() { + Map stats = new HashMap<>(); + + long tenantCount = tenantMapper.selectCount(null); + long activeTenantCount = tenantMapper.selectCount( + new LambdaQueryWrapper().eq(Tenant::getStatus, "active")); + long courseCount = courseMapper.selectCount(null); + long publishedCourseCount = courseMapper.selectCount( + new LambdaQueryWrapper().eq(Course::getStatus, "published")); + + // Monthly lessons (current month) + LocalDate monthStart = LocalDate.now().withDayOfMonth(1); + LocalDate monthEnd = LocalDate.now().withDayOfMonth(LocalDate.now().lengthOfMonth()); + long monthlyLessons = lessonMapper.selectCount( + new LambdaQueryWrapper() + .ge(Lesson::getLessonDate, monthStart) + .le(Lesson::getLessonDate, monthEnd)); + + stats.put("tenantCount", tenantCount); + stats.put("activeTenantCount", activeTenantCount); + stats.put("teacherCount", teacherMapper.selectCount(null)); + stats.put("studentCount", studentMapper.selectCount(null)); + stats.put("courseCount", courseCount); + stats.put("publishedCourseCount", publishedCourseCount); + stats.put("lessonCount", lessonMapper.selectCount(null)); + stats.put("monthlyLessons", monthlyLessons); + return stats; + } + + public List> getTrendData() { + List> trend = new ArrayList<>(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM"); + LocalDate now = LocalDate.now(); + + for (int i = 5; i >= 0; i--) { + LocalDate monthStart = now.minusMonths(i).withDayOfMonth(1); + LocalDate monthEnd = monthStart.withDayOfMonth(monthStart.lengthOfMonth()); + + long lessonCount = lessonMapper.selectCount( + new LambdaQueryWrapper() + .ge(Lesson::getLessonDate, monthStart) + .le(Lesson::getLessonDate, monthEnd)); + + // Count tenants created up to this month end + long tenantCount = tenantMapper.selectCount( + new LambdaQueryWrapper() + .le(Tenant::getCreatedAt, monthEnd.atTime(23, 59, 59))); + + // Count students created up to this month end + long studentCount = studentMapper.selectCount( + new LambdaQueryWrapper() + .le(Student::getCreatedAt, monthEnd.atTime(23, 59, 59))); + + Map point = new HashMap<>(); + point.put("month", monthStart.format(formatter)); + point.put("tenantCount", tenantCount); + point.put("lessonCount", lessonCount); + point.put("studentCount", studentCount); + trend.add(point); + } + return trend; + } + + public List> getActiveTenants(int limit) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(Tenant::getStatus, "active") + .orderByDesc(Tenant::getCreatedAt) + .last("LIMIT " + limit); + List tenants = tenantMapper.selectList(wrapper); + return tenants.stream().map(t -> { + Map map = new HashMap<>(); + map.put("id", t.getId()); + map.put("name", t.getName()); + map.put("code", t.getCode()); + map.put("status", t.getStatus()); + map.put("expireAt", t.getExpireAt()); + // Count teachers and students for this tenant + long teacherCount = teacherMapper.selectCount( + new LambdaQueryWrapper().eq(Teacher::getTenantId, t.getId())); + long studentCount = studentMapper.selectCount( + new LambdaQueryWrapper().eq(Student::getTenantId, t.getId())); + long lessonCount = lessonMapper.selectCount( + new LambdaQueryWrapper().eq(Lesson::getTenantId, t.getId())); + map.put("teacherCount", teacherCount); + map.put("studentCount", studentCount); + map.put("lessonCount", lessonCount); + return map; + }).collect(java.util.stream.Collectors.toList()); + } + + public List> getPopularCourses(int limit) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(Course::getIsSystem, 1) + .eq(Course::getStatus, "published") + .orderByDesc(Course::getCreatedAt) + .last("LIMIT " + limit); + List courses = courseMapper.selectList(wrapper); + return courses.stream().map(c -> { + Map map = new HashMap<>(); + map.put("id", c.getId()); + map.put("name", c.getName()); + map.put("category", c.getCategory()); + map.put("status", c.getStatus()); + map.put("usageCount", c.getUsageCount() != null ? c.getUsageCount() : 0); + map.put("teacherCount", c.getTeacherCount() != null ? c.getTeacherCount() : 0); + return map; + }).collect(java.util.stream.Collectors.toList()); + } + + public List> getRecentActivities(int limit) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.orderByDesc(Lesson::getCreatedAt).last("LIMIT " + limit); + List lessons = lessonMapper.selectList(wrapper); + return lessons.stream().map(l -> { + Map map = new HashMap<>(); + map.put("id", l.getId()); + map.put("title", l.getTitle()); + map.put("lessonDate", l.getLessonDate()); + map.put("status", l.getStatus()); + return map; + }).collect(java.util.stream.Collectors.toList()); + } +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/TenantService.java b/reading-platform-java/src/main/java/com/reading/platform/service/TenantService.java index de261f2..8f5d07f 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/TenantService.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/TenantService.java @@ -25,4 +25,6 @@ public interface TenantService { List getAllActiveTenants(); + String resetSchoolAccountPassword(Long tenantId); + } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/TenantServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/TenantServiceImpl.java index bc09231..8690ca2 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/TenantServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/TenantServiceImpl.java @@ -8,10 +8,13 @@ import com.reading.platform.common.util.PageUtils; import com.reading.platform.dto.request.TenantCreateRequest; import com.reading.platform.dto.request.TenantUpdateRequest; import com.reading.platform.dto.response.TenantResponse; +import com.reading.platform.entity.Teacher; import com.reading.platform.entity.Tenant; +import com.reading.platform.mapper.TeacherMapper; import com.reading.platform.mapper.TenantMapper; import com.reading.platform.service.TenantService; import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; @@ -24,6 +27,8 @@ import java.util.stream.Collectors; public class TenantServiceImpl implements TenantService { private final TenantMapper tenantMapper; + private final TeacherMapper teacherMapper; + private final PasswordEncoder passwordEncoder; @Override @Transactional @@ -33,7 +38,7 @@ public class TenantServiceImpl implements TenantService { new LambdaQueryWrapper().eq(Tenant::getCode, request.getCode()) ); if (existing != null) { - throw new BusinessException(ErrorCode.DATA_ALREADY_EXISTS, "Tenant code already exists"); + throw new BusinessException(ErrorCode.DATA_ALREADY_EXISTS, "Login account already exists"); } Tenant tenant = new Tenant(); @@ -50,6 +55,19 @@ public class TenantServiceImpl implements TenantService { tenant.setStatus("active"); tenantMapper.insert(tenant); + + // Create school login account in teachers table + String defaultPassword = StringUtils.hasText(request.getPassword()) ? request.getPassword() : "123456"; + Teacher schoolAccount = new Teacher(); + schoolAccount.setTenantId(tenant.getId()); + schoolAccount.setUsername(request.getCode()); + schoolAccount.setPassword(passwordEncoder.encode(defaultPassword)); + schoolAccount.setName(request.getName()); + schoolAccount.setStatus("active"); + teacherMapper.insert(schoolAccount); + + // Include temp password in response (cleared text for admin to share) + tenant.setTempPassword(defaultPassword); return tenant; } @@ -117,7 +135,8 @@ public class TenantServiceImpl implements TenantService { ); } if (StringUtils.hasText(status)) { - wrapper.eq(Tenant::getStatus, status); + // Frontend sends uppercase (ACTIVE/SUSPENDED), DB stores lowercase - normalize + wrapper.eq(Tenant::getStatus, status.toLowerCase()); } wrapper.orderByDesc(Tenant::getCreatedAt); @@ -131,6 +150,24 @@ public class TenantServiceImpl implements TenantService { tenantMapper.deleteById(id); } + @Override + @Transactional + public String resetSchoolAccountPassword(Long tenantId) { + Tenant tenant = getTenantById(tenantId); + // Find the school account (username = tenant code) + Teacher schoolAccount = teacherMapper.selectOne( + new LambdaQueryWrapper() + .eq(Teacher::getTenantId, tenantId) + .eq(Teacher::getUsername, tenant.getCode()) + ); + String newPassword = "123456"; + if (schoolAccount != null) { + schoolAccount.setPassword(passwordEncoder.encode(newPassword)); + teacherMapper.updateById(schoolAccount); + } + return newPassword; + } + @Override public List getAllActiveTenants() { List tenants = tenantMapper.selectList( @@ -147,16 +184,16 @@ public class TenantServiceImpl implements TenantService { return TenantResponse.builder() .id(tenant.getId()) .name(tenant.getName()) - .code(tenant.getCode()) - .contactName(tenant.getContactName()) + .loginAccount(tenant.getCode()) + .contactPerson(tenant.getContactName()) .contactPhone(tenant.getContactPhone()) .contactEmail(tenant.getContactEmail()) .address(tenant.getAddress()) .logoUrl(tenant.getLogoUrl()) .status(tenant.getStatus()) - .expireAt(tenant.getExpireAt()) - .maxStudents(tenant.getMaxStudents()) - .maxTeachers(tenant.getMaxTeachers()) + .expireDate(tenant.getExpireAt()) + .studentQuota(tenant.getMaxStudents()) + .teacherQuota(tenant.getMaxTeachers()) .createdAt(tenant.getCreatedAt()) .build(); } From 8b7615bcf1cb1f801299d78ee1cd3429b55a9251 Mon Sep 17 00:00:00 2001 From: tonytech Date: Mon, 2 Mar 2026 15:41:58 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix(auth):=20=E4=BF=AE=E5=A4=8D=E5=AD=A6?= =?UTF-8?q?=E6=A0=A1=E8=B4=A6=E5=8F=B7=E7=99=BB=E5=BD=95=E8=A7=92=E8=89=B2?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E9=94=99=E8=AF=AF=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit loginWithRole()中SCHOOL/TEACHER分支改为返回请求中指定的role(school或teacher), 而非硬编码"teacher"。同步修复getCurrentUserInfo()和changePassword()支持"school"角色。 Co-Authored-By: Claude Sonnet 4.6 --- .../platform/service/impl/AuthServiceImpl.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/AuthServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/AuthServiceImpl.java index e3f7d7e..7f8f08c 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/AuthServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/AuthServiceImpl.java @@ -193,10 +193,11 @@ public class AuthServiceImpl implements AuthService { teacher.setLastLoginAt(LocalDateTime.now()); teacherMapper.updateById(teacher); + // Use the requested role (school or teacher) from the login request JwtPayload payload = JwtPayload.builder() .userId(teacher.getId()) .username(teacher.getUsername()) - .role("teacher") + .role(role) .tenantId(teacher.getTenantId()) .name(teacher.getName()) .build(); @@ -206,7 +207,7 @@ public class AuthServiceImpl implements AuthService { .userId(teacher.getId()) .username(teacher.getUsername()) .name(teacher.getName()) - .role("teacher") + .role(role) .tenantId(teacher.getTenantId()) .build(); } @@ -263,7 +264,7 @@ public class AuthServiceImpl implements AuthService { .tenantId(null) .build(); } - case "teacher" -> { + case "teacher", "school" -> { Teacher teacher = teacherMapper.selectById(payload.getUserId()); yield UserInfoResponse.builder() .id(teacher.getId()) @@ -272,7 +273,7 @@ public class AuthServiceImpl implements AuthService { .email(teacher.getEmail()) .phone(teacher.getPhone()) .avatarUrl(teacher.getAvatarUrl()) - .role("teacher") + .role(role) .tenantId(teacher.getTenantId()) .build(); } @@ -308,7 +309,7 @@ public class AuthServiceImpl implements AuthService { adminUser.setPassword(passwordEncoder.encode(newPassword)); adminUserMapper.updateById(adminUser); } - case "teacher" -> { + case "teacher", "school" -> { Teacher teacher = teacherMapper.selectById(userId); if (!passwordEncoder.matches(oldPassword, teacher.getPassword())) { throw new BusinessException(ErrorCode.OLD_PASSWORD_ERROR);