Compare commits

...

2 Commits

Author SHA1 Message Date
En
d6f66135f6 feat: 学生管理支持家长信息关联
- StudentResponse 新增 parentName 和 parentPhone 字段
- StudentCreateRequest/StudentUpdateRequest 新增家长信息字段
- 学生列表和详情接口返回关联的家长信息
- 创建/更新学生时自动处理家长账号和关联关系
- 支持根据手机号识别已存在家长,避免重复创建

修复学校端学生管理页面家长信息不展示的问题

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 20:49:59 +08:00
En
871f352a4b 优化 2026-03-23 19:59:23 +08:00
6 changed files with 187 additions and 5 deletions

View File

@ -134,11 +134,6 @@ public enum LogModule {
*/
STUDENT_RECORD("学生记录"),
/**
* 阿里云 IMM 服务
*/
IMM("阿里云 IMM 服务"),
/**
* 其他未分类的模块
*/

View File

@ -5,6 +5,8 @@ import com.reading.platform.common.annotation.Log;
import com.reading.platform.common.enums.LogModule;
import com.reading.platform.common.enums.LogOperationType;
import com.reading.platform.common.mapper.StudentMapper;
import com.reading.platform.mapper.ParentMapper;
import com.reading.platform.mapper.ParentStudentMapper;
import com.reading.platform.common.response.PageResult;
import com.reading.platform.common.response.Result;
import com.reading.platform.common.security.SecurityUtils;
@ -34,6 +36,8 @@ public class SchoolStudentController {
private final StudentService studentService;
private final ClassService classService;
private final StudentMapper studentMapper;
private final ParentMapper parentMapper;
private final ParentStudentMapper parentStudentMapper;
@Operation(summary = "Create student")
@Log(module = LogModule.STUDENT, type = LogOperationType.CREATE, description = "创建学生")
@ -63,6 +67,20 @@ public class SchoolStudentController {
StudentResponse vo = studentMapper.toVO(student);
var clazz = classService.getPrimaryClassByStudentId(id);
vo.setClassId(clazz != null ? clazz.getId() : null);
// 设置家长信息查询主要监护人
var parentRelation = parentStudentMapper.selectOne(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.reading.platform.entity.ParentStudent>()
.eq(com.reading.platform.entity.ParentStudent::getStudentId, id)
.eq(com.reading.platform.entity.ParentStudent::getIsPrimary, 1)
.last("LIMIT 1")
);
if (parentRelation != null) {
var parent = parentMapper.selectById(parentRelation.getParentId());
vo.setParentName(parent != null ? parent.getName() : null);
vo.setParentPhone(parent != null ? parent.getPhone() : null);
}
return Result.success(vo);
}
@ -79,8 +97,22 @@ public class SchoolStudentController {
Page<Student> page = studentService.getStudentPage(tenantId, pageNum, pageSize, keyword, grade, status, classId);
List<StudentResponse> voList = studentMapper.toVO(page.getRecords());
for (StudentResponse vo : voList) {
// 设置班级
var clazz = classService.getPrimaryClassByStudentId(vo.getId());
vo.setClassId(clazz != null ? clazz.getId() : null);
// 设置家长信息查询主要监护人
var parentRelation = parentStudentMapper.selectOne(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.reading.platform.entity.ParentStudent>()
.eq(com.reading.platform.entity.ParentStudent::getStudentId, vo.getId())
.eq(com.reading.platform.entity.ParentStudent::getIsPrimary, 1)
.last("LIMIT 1")
);
if (parentRelation != null) {
var parent = parentMapper.selectById(parentRelation.getParentId());
vo.setParentName(parent != null ? parent.getName() : null);
vo.setParentPhone(parent != null ? parent.getPhone() : null);
}
}
return Result.success(PageResult.of(voList, page.getTotal(), page.getCurrent(), page.getSize()));
}

View File

@ -38,4 +38,10 @@ public class StudentCreateRequest {
@Schema(description = "所在班级 ID创建后分配到该班级")
private Long classId;
@Schema(description = "家长姓名")
private String parentName;
@Schema(description = "家长电话")
private String parentPhone;
}

View File

@ -42,4 +42,10 @@ public class StudentUpdateRequest {
@Schema(description = "所在班级 ID更新时调用 assignStudents 调整班级")
private Long classId;
@Schema(description = "家长姓名")
private String parentName;
@Schema(description = "家长电话")
private String parentPhone;
}

View File

@ -60,4 +60,10 @@ public class StudentResponse {
@Schema(description = "更新时间")
private LocalDateTime updatedAt;
@Schema(description = "家长姓名")
private String parentName;
@Schema(description = "家长电话")
private String parentPhone;
}

View File

@ -7,9 +7,11 @@ import com.reading.platform.common.enums.ErrorCode;
import com.reading.platform.common.exception.BusinessException;
import com.reading.platform.dto.request.StudentCreateRequest;
import com.reading.platform.dto.request.StudentUpdateRequest;
import com.reading.platform.entity.Parent;
import com.reading.platform.entity.ParentStudent;
import com.reading.platform.entity.Student;
import com.reading.platform.entity.StudentClassHistory;
import com.reading.platform.mapper.ParentMapper;
import com.reading.platform.mapper.ParentStudentMapper;
import com.reading.platform.mapper.StudentClassHistoryMapper;
import com.reading.platform.mapper.StudentMapper;
@ -24,6 +26,7 @@ import org.springframework.util.StringUtils;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
/**
* 学生服务实现类
@ -36,6 +39,7 @@ public class StudentServiceImpl extends com.baomidou.mybatisplus.extension.servi
private final StudentMapper studentMapper;
private final ParentStudentMapper parentStudentMapper;
private final ParentMapper parentMapper;
private final StudentClassHistoryMapper studentClassHistoryMapper;
private final ClassService classService;
@ -62,6 +66,62 @@ public class StudentServiceImpl extends com.baomidou.mybatisplus.extension.servi
classService.assignStudentToClass(student.getId(), request.getClassId(), tenantId);
}
// 处理家长信息如果提供了家长姓名和电话创建家长账号并关联
if (StringUtils.hasText(request.getParentName()) && StringUtils.hasText(request.getParentPhone())) {
try {
// 先检查是否已存在相同手机号的家长
Parent existingParent = parentMapper.selectOne(
new LambdaQueryWrapper<Parent>()
.eq(Parent::getPhone, request.getParentPhone())
.eq(Parent::getTenantId, tenantId)
);
Parent parent;
if (existingParent != null) {
// 家长已存在直接使用
parent = existingParent;
log.info("家长已存在,手机号:{}, ID: {}", request.getParentPhone(), existingParent.getId());
} else {
// 创建新家长账号
parent = new Parent();
parent.setTenantId(tenantId);
parent.setName(request.getParentName());
parent.setPhone(request.getParentPhone());
// 使用手机号作为登录账号默认密码 123456
parent.setUsername(request.getParentPhone());
// 密码需要加密这里先使用明文实际应该使用 BCrypt 等加密
parent.setPassword("123456");
parent.setStatus(GenericStatus.ACTIVE.getCode());
parentMapper.insert(parent);
log.info("家长账号创建成功ID: {}", parent.getId());
}
// 检查是否已存在关联
Long finalParentId = parent.getId();
Long existingRelationId = Optional.ofNullable(
parentStudentMapper.selectOne(
new LambdaQueryWrapper<ParentStudent>()
.eq(ParentStudent::getParentId, finalParentId)
.eq(ParentStudent::getStudentId, student.getId())
)
).map(ParentStudent::getId).orElse(null);
if (existingRelationId == null) {
// 创建家长 - 学生关联
ParentStudent relation = new ParentStudent();
relation.setParentId(parent.getId());
relation.setStudentId(student.getId());
relation.setRelationship("父子/母子"); // 默认关系后续可扩展
relation.setIsPrimary(1); // 默认为主要监护人
parentStudentMapper.insert(relation);
log.info("家长 - 学生关联创建成功ParentId: {}, StudentId: {}", parent.getId(), student.getId());
}
} catch (Exception e) {
log.error("处理家长信息失败:{}", e.getMessage(), e);
// 不抛出异常避免影响学生创建
}
}
log.info("学生创建成功ID: {}", student.getId());
return student;
}
@ -110,6 +170,83 @@ public class StudentServiceImpl extends com.baomidou.mybatisplus.extension.servi
classService.assignStudentToClass(id, request.getClassId(), student.getTenantId());
}
// 处理家长信息更新
if (StringUtils.hasText(request.getParentName()) && StringUtils.hasText(request.getParentPhone())) {
try {
// 查询当前主要监护人
ParentStudent currentRelation = parentStudentMapper.selectOne(
new LambdaQueryWrapper<ParentStudent>()
.eq(ParentStudent::getStudentId, id)
.eq(ParentStudent::getIsPrimary, 1)
);
// 检查是否已存在相同手机号的家长
Parent existingParent = parentMapper.selectOne(
new LambdaQueryWrapper<Parent>()
.eq(Parent::getPhone, request.getParentPhone())
.eq(Parent::getTenantId, student.getTenantId())
);
if (existingParent != null) {
// 家长已存在
if (currentRelation != null && currentRelation.getParentId().equals(existingParent.getId())) {
// 同一个家长只需更新姓名
if (!existingParent.getName().equals(request.getParentName())) {
existingParent.setName(request.getParentName());
parentMapper.updateById(existingParent);
}
} else {
// 更换监护人先删除旧关联再创建新关联
if (currentRelation != null) {
parentStudentMapper.deleteById(currentRelation.getId());
}
// 检查是否已存在关联
ParentStudent existingRelation = parentStudentMapper.selectOne(
new LambdaQueryWrapper<ParentStudent>()
.eq(ParentStudent::getParentId, existingParent.getId())
.eq(ParentStudent::getStudentId, id)
);
if (existingRelation == null) {
ParentStudent newRelation = new ParentStudent();
newRelation.setParentId(existingParent.getId());
newRelation.setStudentId(id);
newRelation.setRelationship("父子/母子");
newRelation.setIsPrimary(1);
parentStudentMapper.insert(newRelation);
}
}
} else {
// 家长不存在创建新家长账号
Parent parent = new Parent();
parent.setTenantId(student.getTenantId());
parent.setName(request.getParentName());
parent.setPhone(request.getParentPhone());
parent.setUsername(request.getParentPhone());
parent.setPassword("123456");
parent.setStatus(GenericStatus.ACTIVE.getCode());
parentMapper.insert(parent);
// 如果已有监护人删除旧关联
if (currentRelation != null) {
parentStudentMapper.deleteById(currentRelation.getId());
}
// 创建新关联
ParentStudent newRelation = new ParentStudent();
newRelation.setParentId(parent.getId());
newRelation.setStudentId(id);
newRelation.setRelationship("父子/母子");
newRelation.setIsPrimary(1);
parentStudentMapper.insert(newRelation);
}
log.info("家长信息更新成功");
} catch (Exception e) {
log.error("处理家长信息失败:{}", e.getMessage(), e);
// 不抛出异常避免影响学生更新
}
}
log.info("学生更新成功ID: {}", id);
return student;
}