package com.yunhai.cms.service.impl; import com.yunhai.cms.model.vo.SchoolVo; import com.yunhai.cms.model.vo.SiteVo; import com.yunhai.cms.repository.CmsArticleRepository; import com.yunhai.platform.apistd.BizException; import com.yunhai.platform.openapi.client.YschBaseOpenApi; import com.yunhai.platform.utils.exception.ErrorCode; import com.yunhai.platform.utils.model.BoaGroup; import com.yunhai.platform.utils.model.BoaUser; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * 学校工作台(docs/09 §3.3,方案A 双层壳): * ① listFor —— 学校卡片 = 顶层站点(主站),院系子站经 parentSiteId 归属; * 权限语义与 {@link SiteService#listFor} 完全一致(超管全部 / 校级本校 / 无角色空)。 * ② schoolOptions —— 「添加学校」选择器:代理 UserBase oapi getGroupTree 过滤 type=2(学校组), * 只绑定不跨系统写(D6-4);平台不可达降级空数组(CmsUserCenterService 同款)。 */ @Slf4j @Service @RequiredArgsConstructor public class SchoolService { /** UserBase GroupTypeEnum.SCHOOL_GROUP:学校组节点类型 */ private static final int GROUP_TYPE_SCHOOL = 2; private final SiteService siteService; private final CmsArticleRepository articleRepository; /** 学校工作台列表:当前用户可见的顶层站点逐站聚合成学校卡片 */ public List listFor(BoaUser user) { List sites = siteService.listFor(user); List result = new ArrayList<>(); for (SiteVo top : sites) { if (top.getParentSiteId() != null && top.getParentSiteId() > 0) { continue; } SchoolVo vo = new SchoolVo(); vo.setSchId(top.getSchId()); vo.setSchName(top.getSchName()); vo.setMainSiteId(top.getId()); vo.setMainSiteCode(top.getCode()); vo.setMainSiteName(top.getName()); vo.setTheme(top.getTheme()); vo.setStatus(top.getStatus()); // 院系子站按 parentSiteId 归属(同权限范围内统计) long articleCount = 0; int siteCount = 1; for (SiteVo s : sites) { if (s.getParentSiteId() != null && top.getId().equals(s.getParentSiteId())) { siteCount++; } } for (SiteVo s : sites) { boolean own = s.getId().equals(top.getId()); boolean child = s.getParentSiteId() != null && top.getId().equals(s.getParentSiteId()); if (own || child) { articleCount += articleRepository.countBySiteId(s.getId()); } } vo.setSiteCount(siteCount); vo.setArticleCount(articleCount); result.add(vo); } result.sort((a, b) -> Integer.compare(a.getMainSiteId(), b.getMainSiteId())); return result; } /** UserBase 学校选项(仅超管;添加学校=绑定已有学校,不新建) */ public List schoolOptions(BoaUser user) { siteService.requireSuperAdmin(user); BoaGroup root; try { root = YschBaseOpenApi.getGroupTree(); } catch (Exception e) { log.warn("[cms] 获取 UserBase 学校组树失败,学校选项降级为空: {}", e.getMessage()); return Collections.emptyList(); } List options = new ArrayList<>(); collectSchools(root, options); return options; } private void collectSchools(BoaGroup node, List out) { if (node == null) { return; } if (node.getType() != null && node.getType() == GROUP_TYPE_SCHOOL) { out.add(new SchoolVo.Option(node.getId(), node.getName())); } if (node.getChildren() != null) { for (BoaGroup child : node.getChildren()) { collectSchools(child, out); } } } /** 工作台卡片挂载的站点摘要(供校名下拉/快速切换;权限复用 listFor) */ public Map> sitesGroupedByMain(BoaUser user) { List sites = siteService.listFor(user); Map> grouped = new LinkedHashMap<>(); for (SiteVo s : sites) { Integer mainId = (s.getParentSiteId() == null || s.getParentSiteId() <= 0) ? s.getId() : s.getParentSiteId(); grouped.computeIfAbsent(mainId, k -> new ArrayList<>()).add(s); } return grouped; } }