fix(identity): 可选身份列表排序改为「主校置顶→其他校 schId 升序→校内 roleId 升序」
build / build-push (push) Successful in 56s

修复同校多身份被主身份提升拆到头尾(如云海小学教师置顶、管理员落尾)。新增 IdentityService.sortForDisplay 统一 /oapi/user/roles 与 /oapi/identity/available 顺序;主身份行不再单独置顶,主校内部一律按 roleId(老师1→校领导2→管理员7),其余学校按 schId 升序。
This commit is contained in:
chenxing
2026-10-09 17:36:26 +08:00
parent 705cbde7cf
commit 96855a8565
3 changed files with 31 additions and 17 deletions
@@ -56,7 +56,8 @@ public class IdentityController {
} }
/** /**
* 用户全部可选身份(正常态),按 主身份优先 → sortNo → id 排序,供「切换身份」页渲染。 * 用户全部可选身份(正常态),按 主身份所在学校置顶 → 其他学校 schoolId 升序 → 校内 roleId 升序,
* 供「切换身份」页渲染。
*/ */
@GetMapping("available") @GetMapping("available")
public List<BoaRoleInfo> available(@RequestParam("userId") Integer userId) { public List<BoaRoleInfo> available(@RequestParam("userId") Integer userId) {
@@ -76,17 +76,12 @@ public class IdentityService {
/** /**
* 用户全部可选身份(正常态),用于「切换身份」页渲染。 * 用户全部可选身份(正常态),用于「切换身份」页渲染。
* 排序:主身份优先 → sortNo 升序 → id 升序(「未切换默认第一个」的确定性保证)。 * 排序见 {@link #sortForDisplay}:主身份所在学校置顶 → 其他学校 schoolId 升序 → 校内 roleId 升序。
*/ */
public List<BoaRoleInfo> listAvailable(Integer userId) { public List<BoaRoleInfo> listAvailable(Integer userId) {
List<SysUserRoleRel> rels = sysUserRoleRelRepository.findByUserIdAndStatus(userId, StatusEnum.NORMAL); List<SysUserRoleRel> rels = sysUserRoleRelRepository.findByUserIdAndStatus(userId, StatusEnum.NORMAL);
SysUserRoleRel main = resolveMainIdentity(userId); SysUserRoleRel main = resolveMainIdentity(userId);
List<SysUserRoleRel> sorted = rels.stream() List<SysUserRoleRel> sorted = sortForDisplay(rels, main);
.sorted(Comparator.comparingInt((SysUserRoleRel r) ->
main != null && Objects.equals(r.getId(), main.getId()) ? 0 : 1)
.thenComparingInt(SysUserRoleRel::getSortNo)
.thenComparingInt(SysUserRoleRel::getId))
.collect(Collectors.toList());
List<BoaRoleInfo> result = new ArrayList<>(sorted.size()); List<BoaRoleInfo> result = new ArrayList<>(sorted.size());
for (SysUserRoleRel rel : sorted) { for (SysUserRoleRel rel : sorted) {
result.add(toBoaRoleInfo(rel.getRoleId(), rel.getSchoolId())); result.add(toBoaRoleInfo(rel.getRoleId(), rel.getSchoolId()));
@@ -94,6 +89,27 @@ public class IdentityService {
return result; return result;
} }
/**
* 身份列表展示排序({@link #listAvailable} 与 {@code SysUserService#findUserRoles} 共用,保证两接口同序):<br>
* ① 主身份所在学校整体置顶(主身份是该校教师或管理员均成立);<br>
* ② 其余学校按 schoolId 升序;<br>
* ③ 校内按 roleId 升序(老师1 → 校领导2 → 管理员7);<br>
* ④ 兜底 id 升序。<br>
* 主身份行<b>不再单独置顶</b>:主校内部一律按 roleId,故主身份为管理员时该校教师仍排其前。
* 「未切换默认激活身份」由 {@link #getCurrent} 独立解析,不依赖本列表首元素。
*/
public static List<SysUserRoleRel> sortForDisplay(List<SysUserRoleRel> rels, SysUserRoleRel main) {
Integer mainSchoolId = main != null ? main.getSchoolId() : null;
return rels.stream()
.sorted(Comparator
.comparingInt((SysUserRoleRel r) ->
Objects.equals(r.getSchoolId(), mainSchoolId) ? 0 : 1)
.thenComparingInt(SysUserRoleRel::getSchoolId)
.thenComparingInt(SysUserRoleRel::getRoleId)
.thenComparingInt(SysUserRoleRel::getId))
.collect(Collectors.toList());
}
/** /**
* 当前激活身份:优先读 sys_user_current_role;无切换记录时兜底主身份(动态解析,替代 is_main 物化字段)。 * 当前激活身份:优先读 sys_user_current_role;无切换记录时兜底主身份(动态解析,替代 is_main 物化字段)。
* 连主身份都没有时返回 null(前端引导创建身份)。<br><br> * 连主身份都没有时返回 null(前端引导创建身份)。<br><br>
@@ -727,7 +727,8 @@ public class SysUserService implements ISysUserService {
return new HashSet<>(sysGroupService.resolveSchoolIds(groupIds).values()); return new HashSet<>(sysGroupService.resolveSchoolIds(groupIds).values());
} }
/** 身份行展示顺序:主身份优先 → sortNo → id(与 IdentityService.getUserRoles 同序)。 */ /** 管理端列表「用户身份」单值列取首行用的顺序:主身份优先 → sortNo → id。
* 注意:这与面向用户的身份列表 {@link IdentityService#sortForDisplay}(主校置顶 → 校内 roleId)不同,刻意保持。 */
private Comparator<SysUserRoleRel> identityRowOrder(SysUserRoleRel mainRel) { private Comparator<SysUserRoleRel> identityRowOrder(SysUserRoleRel mainRel) {
return Comparator.comparingInt((SysUserRoleRel r) -> return Comparator.comparingInt((SysUserRoleRel r) ->
mainRel != null && Objects.equals(r.getId(), mainRel.getId()) ? 0 : 1) mainRel != null && Objects.equals(r.getId(), mainRel.getId()) ? 0 : 1)
@@ -1486,16 +1487,12 @@ public class SysUserService implements ISysUserService {
if (userId == null) { if (userId == null) {
throw new DException("用户ID不能为空"); throw new DException("用户ID不能为空");
} }
// 数据源:sys_user_role_rel(平台身份角色权威源),内存排序 主身份优先 → sortNo → id // 数据源:sys_user_role_rel(平台身份角色权威源),内存排序与 /oapi/identity/available 同序:
// (修正:此前误读 sys_user_app_role_rel 业务权限角色 + 主归属组当学校,导致「本组」bug) // 主身份所在学校置顶 → 其他学校 schoolId 升序 → 校内 roleId 升序(见 IdentityService#sortForDisplay)
// (修正历史:此前误读 sys_user_app_role_rel 业务权限角色 + 主归属组当学校,导致「本组」bug)
List<SysUserRoleRel> rels = sysUserRoleRelRepository.findByUserIdAndStatus(userId, StatusEnum.NORMAL); List<SysUserRoleRel> rels = sysUserRoleRelRepository.findByUserIdAndStatus(userId, StatusEnum.NORMAL);
SysUserRoleRel mainRel = identityService.resolveMainIdentity(userId); SysUserRoleRel mainRel = identityService.resolveMainIdentity(userId);
List<SysUserRoleRel> sorted = rels.stream() List<SysUserRoleRel> sorted = IdentityService.sortForDisplay(rels, mainRel);
.sorted(Comparator.comparingInt((SysUserRoleRel r) ->
mainRel != null && Objects.equals(r.getId(), mainRel.getId()) ? 0 : 1)
.thenComparingInt(SysUserRoleRel::getSortNo)
.thenComparingInt(SysUserRoleRel::getId))
.collect(Collectors.toList());
List<BoaRoleInfo> result = new ArrayList<>(sorted.size()); List<BoaRoleInfo> result = new ArrayList<>(sorted.size());
for (SysUserRoleRel rel : sorted) { for (SysUserRoleRel rel : sorted) {
BoaRoleInfo info = new BoaRoleInfo(); BoaRoleInfo info = new BoaRoleInfo();