Files
CampusNotice/src/main/java/com/yunhai/campusnotice/service/impl/UserCenterService.java
T
wanghu 3016a97f1b
build / build-push (push) Failing after 1m18s
通知
2026-09-10 15:39:41 +08:00

268 lines
11 KiB
Java

package com.yunhai.campusnotice.service.impl;
import com.yunhai.campusnotice.model.SchTeaList;
import com.yunhai.campusnotice.service.IClassService;
import com.yunhai.campusnotice.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.*;
import java.util.stream.Collectors;
/**
* 用户中心门面服务实现。
* <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. bschclass 全部教师,按 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 → 树结构(modId/page/children),对齐前端 layout 期望
return buildModuleTree(modules);
}
/**
* 将扁平模块列表组装为树(对应原 NoticeController.buildModuleTree)。
* 顶层取 parentId=0 或父节点不在列表中的节点,子节点按 orderNumber 排序。
*/
private List<Map<String, Object>> buildModuleTree(List<BoaModule> modules) {
Map<Integer, BoaModule> moduleMap = modules.stream()
.collect(Collectors.toMap(BoaModule::getId, m -> m, (a, b) -> a));
// 每个模块节点(含 children 占位)
Map<Integer, Map<String, Object>> nodeMap = new LinkedHashMap<>();
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", new ArrayList<>());
nodeMap.put(m.getId(), node);
}
// 挂父子关系
List<Map<String, Object>> roots = new ArrayList<>();
for (BoaModule m : modules) {
Map<String, Object> node = nodeMap.get(m.getId());
int parentId = m.getParentId() != null ? m.getParentId() : 0;
if (parentId == 0 || !moduleMap.containsKey(parentId)) {
roots.add(node);
} else {
@SuppressWarnings("unchecked")
List<Map<String, Object>> children = (List<Map<String, Object>>) nodeMap.get(parentId).get("children");
children.add(node);
}
}
// 保持 SDK(用户中心)返回顺序,不再按 orderNumber 重排
return roots;
}
}