feat(school): 教师管理前后端对齐 - 支持loginAccount/classIds字段
- TeacherCreateRequest: 添加@JsonAlias(loginAccount)支持前端字段 - TeacherCreateRequest/UpdateRequest: 支持classIds班级分配 - TeacherResponse: 返回loginAccount、classIds、classNames、lessonCount - 重置密码接口: 自动生成并返回tempPassword - 创建/更新教师时处理class_teacher关联 Made-with: Cursor
This commit is contained in:
parent
81dd74662e
commit
ccce7e66bb
@ -1,7 +1,6 @@
|
||||
package com.reading.platform.controller.school;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.reading.platform.common.mapper.TeacherMapper;
|
||||
import com.reading.platform.common.response.PageResult;
|
||||
import com.reading.platform.common.response.Result;
|
||||
import com.reading.platform.common.security.SecurityUtils;
|
||||
@ -25,14 +24,13 @@ import java.util.List;
|
||||
public class SchoolTeacherController {
|
||||
|
||||
private final TeacherService teacherService;
|
||||
private final TeacherMapper teacherMapper;
|
||||
|
||||
@Operation(summary = "Create teacher")
|
||||
@PostMapping
|
||||
public Result<TeacherResponse> createTeacher(@Valid @RequestBody TeacherCreateRequest request) {
|
||||
Long tenantId = SecurityUtils.getCurrentTenantId();
|
||||
Teacher teacher = teacherService.createTeacher(tenantId, request);
|
||||
return Result.success(teacherMapper.toVO(teacher));
|
||||
return Result.success(teacherService.toTeacherResponse(teacher));
|
||||
}
|
||||
|
||||
@Operation(summary = "Update teacher")
|
||||
@ -40,7 +38,7 @@ public class SchoolTeacherController {
|
||||
public Result<TeacherResponse> updateTeacher(@PathVariable Long id, @RequestBody TeacherUpdateRequest request) {
|
||||
Long tenantId = SecurityUtils.getCurrentTenantId();
|
||||
Teacher teacher = teacherService.updateTeacherWithTenantCheck(id, tenantId, request);
|
||||
return Result.success(teacherMapper.toVO(teacher));
|
||||
return Result.success(teacherService.toTeacherResponse(teacher));
|
||||
}
|
||||
|
||||
@Operation(summary = "Get teacher by ID")
|
||||
@ -48,7 +46,7 @@ public class SchoolTeacherController {
|
||||
public Result<TeacherResponse> getTeacher(@PathVariable Long id) {
|
||||
Long tenantId = SecurityUtils.getCurrentTenantId();
|
||||
Teacher teacher = teacherService.getTeacherByIdWithTenantCheck(id, tenantId);
|
||||
return Result.success(teacherMapper.toVO(teacher));
|
||||
return Result.success(teacherService.toTeacherResponse(teacher));
|
||||
}
|
||||
|
||||
@Operation(summary = "Get teacher page")
|
||||
@ -60,7 +58,7 @@ public class SchoolTeacherController {
|
||||
@RequestParam(required = false) String status) {
|
||||
Long tenantId = SecurityUtils.getCurrentTenantId();
|
||||
Page<Teacher> page = teacherService.getTeacherPage(tenantId, pageNum, pageSize, keyword, status);
|
||||
List<TeacherResponse> voList = teacherMapper.toVO(page.getRecords());
|
||||
List<TeacherResponse> voList = teacherService.toTeacherResponseList(page.getRecords());
|
||||
return Result.success(PageResult.of(voList, page.getTotal(), page.getCurrent(), page.getSize()));
|
||||
}
|
||||
|
||||
@ -74,10 +72,10 @@ public class SchoolTeacherController {
|
||||
|
||||
@Operation(summary = "Reset teacher password")
|
||||
@PostMapping("/{id}/reset-password")
|
||||
public Result<Void> resetPassword(@PathVariable Long id, @RequestParam String newPassword) {
|
||||
public Result<java.util.Map<String, String>> resetPassword(@PathVariable Long id) {
|
||||
Long tenantId = SecurityUtils.getCurrentTenantId();
|
||||
teacherService.resetPasswordWithTenantCheck(id, tenantId, newPassword);
|
||||
return Result.success();
|
||||
String tempPassword = teacherService.resetPasswordAndReturnTemp(id, tenantId);
|
||||
return Result.success(java.util.Map.of("tempPassword", tempPassword));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,15 +1,19 @@
|
||||
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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Schema(description = "教师创建请求")
|
||||
public class TeacherCreateRequest {
|
||||
|
||||
@NotBlank(message = "用户名不能为空")
|
||||
@Schema(description = "用户名")
|
||||
@JsonAlias("loginAccount")
|
||||
@Schema(description = "用户名/登录账号")
|
||||
private String username;
|
||||
|
||||
@NotBlank(message = "密码不能为空")
|
||||
@ -20,6 +24,7 @@ public class TeacherCreateRequest {
|
||||
@Schema(description = "姓名")
|
||||
private String name;
|
||||
|
||||
@NotBlank(message = "手机号不能为空")
|
||||
@Schema(description = "电话")
|
||||
private String phone;
|
||||
|
||||
@ -32,4 +37,7 @@ public class TeacherCreateRequest {
|
||||
@Schema(description = "简介")
|
||||
private String bio;
|
||||
|
||||
@Schema(description = "负责班级ID列表")
|
||||
private List<Long> classIds;
|
||||
|
||||
}
|
||||
|
||||
@ -3,6 +3,8 @@ package com.reading.platform.dto.request;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Schema(description = "教师更新请求")
|
||||
public class TeacherUpdateRequest {
|
||||
@ -28,4 +30,7 @@ public class TeacherUpdateRequest {
|
||||
@Schema(description = "状态")
|
||||
private String status;
|
||||
|
||||
@Schema(description = "负责班级ID列表")
|
||||
private List<Long> classIds;
|
||||
|
||||
}
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
package com.reading.platform.dto.response;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 教师响应
|
||||
@ -21,7 +23,8 @@ public class TeacherResponse {
|
||||
@Schema(description = "租户 ID")
|
||||
private Long tenantId;
|
||||
|
||||
@Schema(description = "用户名")
|
||||
@JsonProperty("loginAccount")
|
||||
@Schema(description = "登录账号")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "姓名")
|
||||
@ -45,6 +48,15 @@ public class TeacherResponse {
|
||||
@Schema(description = "状态")
|
||||
private String status;
|
||||
|
||||
@Schema(description = "负责班级ID列表")
|
||||
private List<Long> classIds;
|
||||
|
||||
@Schema(description = "负责班级名称")
|
||||
private Object classNames;
|
||||
|
||||
@Schema(description = "授课次数")
|
||||
private Integer lessonCount;
|
||||
|
||||
@Schema(description = "最后登录时间")
|
||||
private LocalDateTime lastLoginAt;
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.reading.platform.dto.request.TeacherCreateRequest;
|
||||
import com.reading.platform.dto.request.TeacherUpdateRequest;
|
||||
import com.reading.platform.dto.response.TeacherResponse;
|
||||
import com.reading.platform.entity.Teacher;
|
||||
|
||||
import java.util.List;
|
||||
@ -63,9 +64,24 @@ public interface TeacherService extends IService<Teacher> {
|
||||
*/
|
||||
void resetPasswordWithTenantCheck(Long id, Long tenantId, String newPassword);
|
||||
|
||||
/**
|
||||
* 重置密码并返回临时密码(带租户验证)
|
||||
*/
|
||||
String resetPasswordAndReturnTemp(Long id, Long tenantId);
|
||||
|
||||
/**
|
||||
* 根据 ID 列表查询教师
|
||||
*/
|
||||
List<Teacher> getTeachersByIds(List<Long> teacherIds);
|
||||
|
||||
/**
|
||||
* 转换为教师响应(含班级、授课数等扩展信息)
|
||||
*/
|
||||
TeacherResponse toTeacherResponse(Teacher teacher);
|
||||
|
||||
/**
|
||||
* 批量转换为教师响应
|
||||
*/
|
||||
List<TeacherResponse> toTeacherResponseList(List<Teacher> teachers);
|
||||
|
||||
}
|
||||
|
||||
@ -6,17 +6,28 @@ import com.reading.platform.common.enums.ErrorCode;
|
||||
import com.reading.platform.common.exception.BusinessException;
|
||||
import com.reading.platform.dto.request.TeacherCreateRequest;
|
||||
import com.reading.platform.dto.request.TeacherUpdateRequest;
|
||||
import com.reading.platform.dto.response.TeacherResponse;
|
||||
import com.reading.platform.entity.ClassTeacher;
|
||||
import com.reading.platform.entity.Clazz;
|
||||
import com.reading.platform.entity.Lesson;
|
||||
import com.reading.platform.entity.Teacher;
|
||||
import com.reading.platform.mapper.ClassTeacherMapper;
|
||||
import com.reading.platform.mapper.ClazzMapper;
|
||||
import com.reading.platform.mapper.LessonMapper;
|
||||
import com.reading.platform.mapper.TeacherMapper;
|
||||
import com.reading.platform.service.ClassService;
|
||||
import com.reading.platform.service.TeacherService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 教师服务实现类
|
||||
@ -28,6 +39,11 @@ public class TeacherServiceImpl extends com.baomidou.mybatisplus.extension.servi
|
||||
implements TeacherService {
|
||||
|
||||
private final TeacherMapper teacherMapper;
|
||||
private final com.reading.platform.common.mapper.TeacherMapper teacherVoMapper;
|
||||
private final ClassTeacherMapper classTeacherMapper;
|
||||
private final ClazzMapper clazzMapper;
|
||||
private final LessonMapper lessonMapper;
|
||||
private final ClassService classService;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
|
||||
@Override
|
||||
@ -57,6 +73,18 @@ public class TeacherServiceImpl extends com.baomidou.mybatisplus.extension.servi
|
||||
|
||||
teacherMapper.insert(teacher);
|
||||
|
||||
// 分配教师到班级
|
||||
if (!CollectionUtils.isEmpty(request.getClassIds())) {
|
||||
for (Long classId : request.getClassIds()) {
|
||||
classService.getClassByIdWithTenantCheck(classId, tenantId);
|
||||
ClassTeacher classTeacher = new ClassTeacher();
|
||||
classTeacher.setClassId(classId);
|
||||
classTeacher.setTeacherId(teacher.getId());
|
||||
classTeacher.setRole("MAIN");
|
||||
classTeacherMapper.insert(classTeacher);
|
||||
}
|
||||
}
|
||||
|
||||
log.info("教师创建成功,ID: {}", teacher.getId());
|
||||
return teacher;
|
||||
}
|
||||
@ -92,6 +120,21 @@ public class TeacherServiceImpl extends com.baomidou.mybatisplus.extension.servi
|
||||
|
||||
teacherMapper.updateById(teacher);
|
||||
|
||||
// 更新教师班级分配
|
||||
if (request.getClassIds() != null) {
|
||||
classTeacherMapper.delete(
|
||||
new LambdaQueryWrapper<ClassTeacher>().eq(ClassTeacher::getTeacherId, id)
|
||||
);
|
||||
for (Long classId : request.getClassIds()) {
|
||||
classService.getClassByIdWithTenantCheck(classId, teacher.getTenantId());
|
||||
ClassTeacher classTeacher = new ClassTeacher();
|
||||
classTeacher.setClassId(classId);
|
||||
classTeacher.setTeacherId(id);
|
||||
classTeacher.setRole("MAIN");
|
||||
classTeacherMapper.insert(classTeacher);
|
||||
}
|
||||
}
|
||||
|
||||
log.info("教师更新成功,ID: {}", id);
|
||||
return teacher;
|
||||
}
|
||||
@ -200,6 +243,18 @@ public class TeacherServiceImpl extends com.baomidou.mybatisplus.extension.servi
|
||||
resetPassword(id, newPassword);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public String resetPasswordAndReturnTemp(Long id, Long tenantId) {
|
||||
log.info("开始重置密码并返回临时密码,ID: {}, tenantId: {}", id, tenantId);
|
||||
Teacher teacher = getTeacherByIdWithTenantCheck(id, tenantId);
|
||||
String tempPassword = UUID.randomUUID().toString().replace("-", "").substring(0, 8);
|
||||
teacher.setPassword(passwordEncoder.encode(tempPassword));
|
||||
teacherMapper.updateById(teacher);
|
||||
log.info("密码重置成功,ID: {}", id);
|
||||
return tempPassword;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Teacher> getTeachersByIds(List<Long> teacherIds) {
|
||||
log.debug("根据 ID 列表查询教师,ID 列表:{}", teacherIds);
|
||||
@ -215,4 +270,53 @@ public class TeacherServiceImpl extends com.baomidou.mybatisplus.extension.servi
|
||||
return teacherMapper.selectList(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TeacherResponse toTeacherResponse(Teacher teacher) {
|
||||
if (teacher == null) return null;
|
||||
TeacherResponse response = teacherVoMapper.toVO(teacher);
|
||||
enrichTeacherResponse(response, teacher.getId());
|
||||
return response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TeacherResponse> toTeacherResponseList(List<Teacher> teachers) {
|
||||
if (teachers == null) return null;
|
||||
List<TeacherResponse> list = new ArrayList<>(teachers.size());
|
||||
for (Teacher teacher : teachers) {
|
||||
list.add(toTeacherResponse(teacher));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private void enrichTeacherResponse(TeacherResponse response, Long teacherId) {
|
||||
List<ClassTeacher> classTeachers = classTeacherMapper.selectList(
|
||||
new LambdaQueryWrapper<ClassTeacher>().eq(ClassTeacher::getTeacherId, teacherId)
|
||||
);
|
||||
List<Long> classIds = new ArrayList<>();
|
||||
List<String> classNames = new ArrayList<>();
|
||||
for (ClassTeacher ct : classTeachers) {
|
||||
classIds.add(ct.getClassId());
|
||||
Clazz clazz = clazzMapper.selectById(ct.getClassId());
|
||||
if (clazz != null) {
|
||||
classNames.add(clazz.getName());
|
||||
}
|
||||
}
|
||||
response.setClassIds(classIds);
|
||||
response.setClassNames(classNames.isEmpty() ? null : classNames);
|
||||
|
||||
if ("active".equals(response.getStatus())) {
|
||||
response.setStatus("ACTIVE");
|
||||
}
|
||||
|
||||
long lessonCount = 0;
|
||||
try {
|
||||
lessonCount = lessonMapper.selectCount(
|
||||
new LambdaQueryWrapper<Lesson>().eq(Lesson::getTeacherId, teacherId)
|
||||
);
|
||||
} catch (Exception e) {
|
||||
log.debug("Query lesson count failed: {}", e.getMessage());
|
||||
}
|
||||
response.setLessonCount((int) lessonCount);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user