build / build-push (push) Successful in 2m27s
用户中心已将模块层级经平台 BoaModule.children 下发,本仓原先按 parentId 重建父子 关系的 buildModuleTree 变成空转(且每个子应用各抄一份),现收敛为 toFrontendTree: 只做前端 layout 需要的字段改名(path→page、id→modId、补 usable/orderNumber)并递归 映射 children,层级与兄弟顺序一律以上游为准,本侧不重排。 前端契约不变(children 恒为数组),未触碰任何 .vue/.ts;收到旧版用户中心的扁平结果 (children=null)时退化为与今日一致的扁平菜单,不抛 NPE。
251 lines
10 KiB
Java
251 lines
10 KiB
Java
package com.yunhai.notice.service.impl;
|
|
|
|
import com.yunhai.notice.model.SchTeaList;
|
|
import com.yunhai.notice.service.IClassService;
|
|
import com.yunhai.notice.service.IUserCenterService;
|
|
import com.yunhai.platform.openapi.client.YschBaseOpenApi;
|
|
import com.yunhai.platform.apistd.BizException;
|
|
import com.yunhai.platform.utils.exception.ErrorCode;
|
|
import com.yunhai.platform.utils.model.BoaGroup;
|
|
import com.yunhai.platform.utils.model.BoaModule;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.stereotype.Service;
|
|
|
|
import java.util.*;
|
|
|
|
/**
|
|
* 用户中心门面服务实现。
|
|
* <p>原 BaseApiController.getSchoolAll 的组树组装、教师挂组、递归建树、排序逻辑整体下沉至此;
|
|
* GetGroupUser 空桩改为显式报错(未接入用户中心对应开放接口时提示,而非静默返回空列表)。
|
|
* 跨仓调用统一收敛到 {@link YschBaseOpenApi} 门面,Controller 不再直接静态调用。</p>
|
|
*/
|
|
@Service
|
|
public class UserCenterService implements IUserCenterService {
|
|
|
|
private static final Logger log = LoggerFactory.getLogger(UserCenterService.class);
|
|
|
|
/** 学生组(UserBase GroupTypeEnum.STUDENT_GROUP),组树中剔除 */
|
|
private static final int GROUP_TYPE_STUDENT = 8;
|
|
|
|
@Autowired
|
|
private IClassService classService;
|
|
|
|
// ============================ 学校组织树 ============================
|
|
|
|
@Override
|
|
public List<Map<String, Object>> getSchoolAllTree(Integer schId) {
|
|
if (schId == null) {
|
|
throw new BizException(ErrorCode.PARAM_ERROR, "获取学校信息失败");
|
|
}
|
|
|
|
// 1. userbase 组树(整棵学校子树),剔除学生组
|
|
List<Map<String, Object>> flatNodes = new ArrayList<>();
|
|
BoaGroup root = YschBaseOpenApi.getGroupById(schId, true);
|
|
if (root == null) {
|
|
log.warn("[getSchoolAll] 用户中心未找到学校组, schId={}", schId);
|
|
return Collections.emptyList();
|
|
}
|
|
flattenGroup(root, 0, flatNodes);
|
|
|
|
// 2. userclass(班级管理)全部教师,按 GroupIds 挂到对应组下;无有效组的兜底挂学校根节点
|
|
Set<Integer> treeGroupIds = new HashSet<>();
|
|
for (Map<String, Object> node : flatNodes) {
|
|
treeGroupIds.add((Integer) node.get("id"));
|
|
}
|
|
Map<Integer, SchTeaList> teacherMap = new LinkedHashMap<>();
|
|
Map<Integer, Set<Integer>> teacherPids = new LinkedHashMap<>();
|
|
List<SchTeaList> teachers = classService.getSchTeaList(schId);
|
|
for (SchTeaList tea : teachers) {
|
|
if (tea.getUserTeaSerID() == null) {
|
|
continue;
|
|
}
|
|
// 同一教师多行(多组/接口重复数据)合并,按 (教师, 组) 去重
|
|
teacherMap.putIfAbsent(tea.getUserTeaSerID(), tea);
|
|
// 接口现行字段为单个 GroupID,兼容旧字段 GroupIds
|
|
List<Integer> teaGroupIds = tea.getGroupIds();
|
|
if ((teaGroupIds == null || teaGroupIds.isEmpty()) && tea.getGroupId() != null) {
|
|
teaGroupIds = Collections.singletonList(tea.getGroupId());
|
|
}
|
|
if (teaGroupIds != null) {
|
|
for (Integer gid : teaGroupIds) {
|
|
if (gid != null && treeGroupIds.contains(gid)) {
|
|
teacherPids.computeIfAbsent(tea.getUserTeaSerID(), k -> new HashSet<>()).add(gid);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (Map.Entry<Integer, SchTeaList> entry : teacherMap.entrySet()) {
|
|
int teaId = entry.getKey();
|
|
SchTeaList tea = entry.getValue();
|
|
Set<Integer> pids = teacherPids.get(teaId);
|
|
if (pids == null || pids.isEmpty()) {
|
|
// 教师所属组均被剔除(如学生组)或无组信息,挂学校根节点
|
|
pids = new HashSet<>(Collections.singletonList(treeGroupIds.contains(schId) ? schId : 0));
|
|
}
|
|
for (Integer pid : pids) {
|
|
Map<String, Object> node = new LinkedHashMap<>();
|
|
node.put("id", teaId);
|
|
node.put("name", tea.getTeaName() != null ? tea.getTeaName() : "");
|
|
node.put("pid", pid);
|
|
node.put("no", tea.getTeaNo() != null ? tea.getTeaNo() : 0);
|
|
node.put("type", 2);
|
|
node.put("isParent", false);
|
|
node.put("photo", "");
|
|
flatNodes.add(node);
|
|
}
|
|
}
|
|
|
|
// 3. 扁平节点递归组装为树
|
|
return formatUserTree(flatNodes, 0);
|
|
}
|
|
|
|
/**
|
|
* 将 BoaGroup 子树扁平化为组节点列表(type=1);学生组(type=8)整棵剔除。
|
|
* isParent=true 标识组节点,前端 ztree 据此渲染为文件夹。
|
|
*/
|
|
private void flattenGroup(BoaGroup group, int pid, List<Map<String, Object>> nodes) {
|
|
if (group == null || group.getId() == null) {
|
|
return;
|
|
}
|
|
if (group.getType() != null && group.getType() == GROUP_TYPE_STUDENT) {
|
|
return;
|
|
}
|
|
Map<String, Object> node = new LinkedHashMap<>();
|
|
node.put("id", group.getId());
|
|
node.put("name", group.getName() != null ? group.getName() : "");
|
|
node.put("pid", pid);
|
|
node.put("no", group.getSort() != null ? group.getSort() : 0);
|
|
node.put("type", 1);
|
|
node.put("isParent", true);
|
|
node.put("photo", "");
|
|
nodes.add(node);
|
|
|
|
if (group.getChildren() != null) {
|
|
for (BoaGroup child : group.getChildren()) {
|
|
flattenGroup(child, group.getId(), nodes);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 递归构建用户树(对应 C# HttpUserApi.FormatUserTree)。
|
|
* 根层取 pid=0 或父节点不在列表中的节点;type=1 且无子节点的空组剔除。
|
|
*/
|
|
private List<Map<String, Object>> formatUserTree(List<Map<String, Object>> treeList, int pid) {
|
|
List<Map<String, Object>> data;
|
|
if (pid == 0) {
|
|
Set<Integer> allIds = new HashSet<>();
|
|
for (Map<String, Object> n : treeList) {
|
|
allIds.add((Integer) n.get("id"));
|
|
}
|
|
data = new ArrayList<>();
|
|
for (Map<String, Object> n : treeList) {
|
|
int p = (Integer) n.get("pid");
|
|
if (p == 0 || !allIds.contains(p)) {
|
|
data.add(n);
|
|
}
|
|
}
|
|
} else {
|
|
data = new ArrayList<>();
|
|
for (Map<String, Object> n : treeList) {
|
|
if ((Integer) n.get("pid") == pid) {
|
|
data.add(n);
|
|
}
|
|
}
|
|
}
|
|
|
|
List<Map<String, Object>> result = new ArrayList<>();
|
|
for (Map<String, Object> item : data) {
|
|
int itemId = (Integer) item.get("id");
|
|
int itemType = (Integer) item.get("type");
|
|
|
|
List<Map<String, Object>> children = formatUserTree(treeList, itemId);
|
|
|
|
// type=1(组) 且无子节点 → 不加入(C# 逻辑)
|
|
if (itemType == 1 && children.isEmpty()) {
|
|
continue;
|
|
}
|
|
|
|
Map<String, Object> node = new LinkedHashMap<>(item);
|
|
// 仅组节点携带 children;叶子不带该字段,避免 ztree 误判 isParent
|
|
if (itemType == 1) {
|
|
node.put("children", children);
|
|
}
|
|
result.add(node);
|
|
}
|
|
|
|
// 按 no 排序(数字优先,无法解析的排最后)
|
|
result.sort(Comparator.comparingInt(n -> {
|
|
Object no = n.get("no");
|
|
if (no instanceof Integer) {
|
|
return (Integer) no;
|
|
}
|
|
if (no instanceof String) {
|
|
try {
|
|
return Integer.parseInt((String) no);
|
|
} catch (NumberFormatException e) {
|
|
return 9999;
|
|
}
|
|
}
|
|
return 9999;
|
|
}));
|
|
|
|
return result;
|
|
}
|
|
|
|
// ============================ 组内用户 ============================
|
|
|
|
@Override
|
|
public List<Map<String, Object>> getGroupUser(Integer gid, Integer role) {
|
|
if (gid == null) {
|
|
throw new BizException(ErrorCode.PARAM_ERROR, "组ID不得为空");
|
|
}
|
|
log.info("[getGroupUser] gid={}, role={}, 用户中心组内用户开放接口尚未接入", gid, role);
|
|
// 显式报错而非静默返回空列表:原空桩会让前端误以为组内无用户
|
|
throw new BizException(ErrorCode.INTERNAL_SERVER_ERROR, "组内用户查询接口暂未接入用户中心,请联系管理员配置后重试");
|
|
}
|
|
|
|
// ============================ 用户模块树 ============================
|
|
|
|
@Override
|
|
public List<Map<String, Object>> getUserModuleTree(Integer userId, Integer schId) {
|
|
if (userId == null) {
|
|
throw new BizException(ErrorCode.PARAM_ERROR, "用户ID不得为空");
|
|
}
|
|
List<BoaModule> modules = YschBaseOpenApi.getUserModule(userId, schId);
|
|
if (modules == null || modules.isEmpty()) {
|
|
return Collections.emptyList();
|
|
}
|
|
// 用户中心已按 BoaModule.children 下发模块树:本地不再重组层级,仅做前端字段改名映射
|
|
return toFrontendTree(modules);
|
|
}
|
|
|
|
/**
|
|
* BoaModule 树 → 前端 layout 期望的字段形状(递归,<b>只改名不组树</b>)。<br>
|
|
* 层级与兄弟顺序均由用户中心 {@code BoaModule.children} + customId 升序决定,本侧不重排;
|
|
* 叶子节点 children 为空列表(用户中心保证),前端可无判空递归。
|
|
*/
|
|
private List<Map<String, Object>> toFrontendTree(List<BoaModule> modules) {
|
|
List<Map<String, Object>> result = new ArrayList<>();
|
|
if (modules == null || modules.isEmpty()) {
|
|
return result;
|
|
}
|
|
for (BoaModule m : modules) {
|
|
Map<String, Object> node = new LinkedHashMap<>();
|
|
node.put("id", m.getId());
|
|
node.put("modId", m.getId());
|
|
node.put("name", m.getName());
|
|
node.put("parentId", m.getParentId() != null ? m.getParentId() : 0);
|
|
node.put("page", m.getPath() != null ? m.getPath() : "");
|
|
node.put("level", m.getLevel() != null ? m.getLevel() : 0);
|
|
node.put("icon", m.getIcon() != null ? m.getIcon() : "");
|
|
node.put("orderNumber", m.getSortNo() != null ? m.getSortNo() : 0);
|
|
node.put("usable", true);
|
|
node.put("children", toFrontendTree(m.getChildren()));
|
|
result.add(node);
|
|
}
|
|
return result;
|
|
}
|
|
} |