编写开放接口,组/用户,移动组等功能
ci-userbase-service / build-and-push (push) Successful in 2m17s

This commit is contained in:
chenxing
2026-08-18 21:46:06 +08:00
parent 7a1dc29ff7
commit 52b29c5082
10 changed files with 388 additions and 61 deletions
@@ -69,6 +69,9 @@ public class SysUserService implements ISysUserService {
/** 主归属标识:1=本职主学校/部门 */
private static final int IS_MAIN = 1;
/** 开放接口/oapi 写操作无登录态时使用的审计人哨兵值(非真实用户ID),用于兜底 create_user/update_user 的 NOT NULL 约束。 */
private static final int SYSTEM_USER_ID = 0;
/** 系统内置超级管理员账号(与 sys_user_init.sql 种子账号保持一致) */
private static final Set<String> SUPER_ADMIN_ACCOUNTS =
new HashSet<>(Arrays.asList("yunhaisch", "yunhaisch2", "yunhaisch3"));
@@ -136,6 +139,9 @@ public class SysUserService implements ISysUserService {
// disabled 用枚举存储:不传时默认 NORMAL(正常/未禁用)
entity.setDisabled(request.getDisabled() != null ? resolveStatus(request.getDisabled()) : StatusEnum.NORMAL);
entity.setExpired(request.getExpired() != null ? request.getExpired() : false);
// oapi 写操作无登录态时,用系统哨兵值兜底 create_user/update_user(NOT NULL 约束)
entity.setCreateUser(SYSTEM_USER_ID);
entity.setUpdateUser(SYSTEM_USER_ID);
SysUser saved = sysUserRepository.save(entity);
publishUserEvent(PushInterfaceType.ADD_USER, saved.getId());
@@ -183,22 +189,23 @@ public class SysUserService implements ISysUserService {
if (request.getExpired() != null) {
entity.setExpired(request.getExpired());
}
entity.setUpdateUser(SYSTEM_USER_ID);
sysUserRepository.save(entity);
publishUserEvent(PushInterfaceType.UPDATE_USER, id);
}
@Override
@Transactional
public void delete(Integer id) {
if (!sysUserRepository.existsById(id)) {
throw new DException("系统用户不存在");
public List<Integer> batchAdd(List<SysUserRequest> requests) {
if (requests == null || requests.isEmpty()) {
throw new DException("批量新增用户列表不能为空");
}
// 先清理组用户关联、用户-角色绑定,再删除用户
sysUserGroupRelRepository.deleteByUserId(id);
// AI-FIX(角色授权): 删除用户时级联清理用户-业务角色绑定(逻辑外键无物理 FK,避免残留孤儿数据)
sysUserAppRoleRelRepository.deleteByUserIdBulk(id);
sysUserRepository.deleteById(id);
publishUserEvent(PushInterfaceType.DELETE_USER, id);
// 批量新增与单条一致:强制密码强度校验(每条需携带 password + confirmPassword)
List<Integer> ids = new ArrayList<>();
for (SysUserRequest request : requests) {
ids.add(createUser(request, true));
}
return ids;
}
@Override
@@ -384,6 +391,46 @@ public class SysUserService implements ISysUserService {
publishUserEvent(PushInterfaceType.UPDATE_USER, userIds);
}
@Override
@Transactional
public void moveUserWithinSchool(Integer userId, Integer groupId, Integer schoolId) {
if (userId == null) {
throw new DException("用户ID不能为空");
}
if (groupId == null) {
throw new DException("目标组ID不能为空");
}
if (schoolId == null) {
throw new DException("学校ID不能为空");
}
if (!sysUserRepository.existsById(userId)) {
throw new DException("系统用户不存在");
}
if (!sysGroupRepository.existsById(groupId)) {
throw new DException("目标分组不存在");
}
if (!sysGroupRepository.existsById(schoolId)) {
throw new DException("学校分组不存在");
}
// 学校子树范围(含学校自身):用户与目标组都必须落在此范围内,否则视为跨校移动
List<Integer> schoolScope = sysGroupService.listSelfAndDescendantIds(schoolId);
// ① 用户当前必须已在该学校内(至少一个组归属落在 schoolScope)
List<Integer> userGroupIds = findGroupIdsByUserId(userId);
boolean userInSchool = userGroupIds.stream().anyMatch(schoolScope::contains);
if (!userInSchool) {
throw new DException("用户不在该学校范围内,禁止跨校移动");
}
// ② 目标组必须也在该学校内
if (!schoolScope.contains(groupId)) {
throw new DException("目标组不属于该学校范围,禁止跨校移动");
}
// 复用覆盖式改组逻辑(目标设为主组)
changeGroups(Collections.singletonList(userId), Collections.singletonList(groupId));
}
@Override
@Transactional(rollbackFor = Exception.class)
public BatchImportResult batchImport(MultipartFile file) {