本地工作区快照:恢复 .git 仓库(合并远端 main 前基线)

This commit is contained in:
chenxing
2026-08-21 10:46:47 +08:00
commit f182fe44ce
269 changed files with 22450 additions and 0 deletions
@@ -0,0 +1,206 @@
package com.yunhai.userbase.service.impl;
import com.yunhai.platform.utils.model.BoaGroup;
import com.yunhai.platform.utils.model.BoaUser;
import com.yunhai.userbase.entity.SysGroup;
import com.yunhai.userbase.entity.SysUser;
import com.yunhai.userbase.entity.SysUserCurrentRole;
import com.yunhai.userbase.entity.SysUserGroupRel;
import com.yunhai.userbase.entity.SysUserRoleRel;
import com.yunhai.userbase.enums.GroupTypeEnum;
import com.yunhai.userbase.enums.StatusEnum;
import com.yunhai.userbase.repository.SysGroupRepository;
import com.yunhai.userbase.repository.SysUserGroupRelRepository;
import com.yunhai.userbase.repository.SysUserRepository;
import com.yunhai.userbase.repository.SysUserRoleRelRepository;
import com.yunhai.userbase.repository.SysUserCurrentRoleRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
/**
* 用户中心核心服务:把 UserBase 自身的 sys_user / sys_group 组装成基础平台统一的
* {@link BoaUser}(含部门/学校/教育局多级组织)。<br><br>
* 这是「UserBase 由子应用升级为用户中心」的关键:平台侧 {@code UserDetailsProvider}
* ({@code UserBaseUserDetailsProvider})与开放接口({@code OpenBaseController})都复用本服务,
* 保证 CAS 会话流与签名开放流返回的 BoaUser 结构完全一致。
*/
@Service
public class UserCenterService {
/** 虚拟根节点 parentId(与 SysGroupService 约定一致)。 */
private static final int ROOT_PARENT_ID = 0;
@Autowired
private SysUserRepository sysUserRepository;
@Autowired
private SysUserGroupRelRepository sysUserGroupRelRepository;
@Autowired
private SysGroupRepository sysGroupRepository;
@Autowired
private SysUserRoleRelRepository sysUserRoleRelRepository;
@Autowired
private SysUserCurrentRoleRepository sysUserCurrentRoleRepository;
public BoaUser getUserInfoWithDeptByAccount(String account) {
if (account == null) {
return null;
}
return resolve(sysUserRepository.findByAccount(account.trim()));
}
public BoaUser getUserInfoWithDeptByPhone(String phone) {
if (phone == null) {
return null;
}
return resolve(sysUserRepository.findByPhone(phone.trim()));
}
public BoaUser getUserInfoWithDeptById(Integer id) {
if (id == null) {
return null;
}
return resolve(sysUserRepository.findById(id).orElse(null));
}
private BoaUser resolve(SysUser user) {
if (user == null) {
return null;
}
BoaUser boa = new BoaUser();
boa.setId(user.getId());
boa.setAccount(user.getAccount());
boa.setName(user.getRealName());
boa.setIdcard(user.getIdcard());
boa.setPhone(user.getPhone());
boa.setProfilePicture(user.getProfilePicture());
// 用户表无 email / gender 列,置 null
boa.setEmail(null);
boa.setGender(null);
boa.setType(user.getType() != null ? user.getType().getKey() : null);
// 状态语义对齐:本表 disabled(NORMAL=0 正常 / DISABLED=1 禁用) -> BoaUser(1 正常 / 0 禁用)
boa.setStatus(user.getDisabled() == StatusEnum.NORMAL ? 1 : 0);
// 角色列表:从 sys_user_role_rel(平台身份角色权威源)取正常态 roleId 去重,不再读 sys_user.roles
List<Integer> roleIds = sysUserRoleRelRepository
.findDistinctRoleIdsByUserIdAndStatus(user.getId(), StatusEnum.NORMAL);
boa.setRoleIds(roleIds);
List<BoaGroup> groups = buildGroups(user.getId());
boa.setGroups(groups);
// 部门/教育局:仍从组织链推导(与主组/区域组语义绑定)
deriveOrg(groups, boa);
// 学校/当前激活身份/可选学校:从身份关联表推导(school 语义=当前激活学校)
deriveIdentity(user.getId(), boa);
return boa;
}
/**
* 组装用户组织链:取主归属组(isMain=1,否则首个关联),沿 parentId 向上回溯到根,
* 顺序为「主组 -> ... -> 根方向」(近 -> 远)。
*/
private List<BoaGroup> buildGroups(Integer userId) {
List<SysUserGroupRel> rels = sysUserGroupRelRepository.findByUserId(userId);
if (rels == null || rels.isEmpty()) {
return new ArrayList<>();
}
SysUserGroupRel mainRel = rels.stream()
.filter(r -> r.getIsMain() != null && r.getIsMain() == 1)
.findFirst()
.orElse(rels.get(0));
Integer groupId = mainRel.getGroupId();
if (groupId == null) {
return new ArrayList<>();
}
List<BoaGroup> chain = new ArrayList<>();
Integer cursor = groupId;
Set<Integer> seen = new HashSet<>();
while (cursor != null && cursor != ROOT_PARENT_ID && seen.add(cursor)) {
SysGroup g = sysGroupRepository.findById(cursor).orElse(null);
if (g == null) {
break;
}
BoaGroup bg = new BoaGroup();
bg.setId(g.getId());
bg.setName(g.getName());
bg.setParentId(g.getParentId());
bg.setType(g.getType() != null ? g.getType().getKey() : null);
chain.add(bg);
cursor = g.getParentId();
}
return chain;
}
/** 从组织链推导 school / bureau / dept。 */
private void deriveOrg(List<BoaGroup> groups, BoaUser boa) {
if (groups == null || groups.isEmpty()) {
return;
}
BoaGroup school = null;
BoaGroup bureau = null;
for (BoaGroup g : groups) {
if (school == null && Objects.equals(g.getType(), GroupTypeEnum.SCHOOL_GROUP.getKey())) {
school = g;
}
if (bureau == null && Objects.equals(g.getType(), GroupTypeEnum.AREA_GROUP.getKey())) {
bureau = g;
}
}
boa.setSchool(school);
boa.setBureau(bureau);
// 部门:主组(链的近端第一个);若主组本身为学校,则部门即学校
boa.setDept(groups.get(0));
}
/**
* 从身份关联推导当前激活身份与可选学校。school 字段语义=当前激活学校:<br>
* ① 优先读 {@code sys_user_current_role}(用户主动切换后的状态);<br>
* ② 无切换记录时兜底取 {@code sys_user_role_rel.is_main=1} 的整条记录(保证是合法存在的身份,
* 避免「主组+主角色」组合出 B 学校老师的非法身份);<br>
* ③ schools:用户在全部学校下的可选身份去重 schoolId(>0)集合。
*/
private void deriveIdentity(Integer userId, BoaUser boa) {
Integer currentSchoolId = null;
String currentSchoolName = null;
SysUserCurrentRole current = sysUserCurrentRoleRepository.findByUserId(userId).orElse(null);
if (current != null && current.getRoleId() != null) {
currentSchoolId = current.getSchoolId();
currentSchoolName = current.getSchoolName();
} else {
// 兜底:直接取主身份整条记录(isMain=1),而不是「主组+主角色」组合
SysUserRoleRel mainRel = sysUserRoleRelRepository
.findByUserIdAndIsMain(userId, 1).orElse(null);
if (mainRel != null) {
currentSchoolId = mainRel.getSchoolId();
if (currentSchoolId != null && currentSchoolId > 0) {
SysGroup sch = sysGroupRepository.findById(currentSchoolId).orElse(null);
currentSchoolName = sch != null ? sch.getName() : null;
}
}
}
if (currentSchoolId != null && currentSchoolId > 0) {
boa.setSchool(toBoaGroup(currentSchoolId, currentSchoolName));
}
}
/** 组装一个 BoaGroup(仅填充 id 与 name;name 为 null 时回源查 sys_group) */
private BoaGroup toBoaGroup(Integer groupId, String fallbackName) {
BoaGroup bg = new BoaGroup();
bg.setId(groupId);
if (fallbackName != null) {
bg.setName(fallbackName);
} else {
SysGroup g = sysGroupRepository.findById(groupId).orElse(null);
bg.setName(g != null ? g.getName() : null);
}
return bg;
}
}